Skip to content

Commit 39c2e7b

Browse files
committed
Added config file to allow users to specify channel limits as per bolt 2
1 parent 3bcd911 commit 39c2e7b

File tree

5 files changed

+181
-46
lines changed

5 files changed

+181
-46
lines changed

fuzz/fuzz_targets/full_stack_target.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use lightning::util::events::{EventsProvider,Event};
2222
use lightning::util::reset_rng_state;
2323
use lightning::util::logger::Logger;
2424
use lightning::util::sha2::Sha256;
25+
use lightning::util::configurations::UserConfig;
2526

2627
mod utils;
2728

@@ -235,8 +236,10 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
235236
let watch = Arc::new(ChainWatchInterfaceUtil::new(Network::Bitcoin, Arc::clone(&logger)));
236237
let broadcast = Arc::new(TestBroadcaster{});
237238
let monitor = channelmonitor::SimpleManyChannelMonitor::new(watch.clone(), broadcast.clone());
238-
239-
let channelmanager = ChannelManager::new(our_network_key, slice_to_be32(get_slice!(4)), get_slice!(1)[0] != 0, Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone(), Arc::clone(&logger)).unwrap();
239+
let mut config = UserConfig::new();
240+
config.channel_options.fee_proportional_millionths = slice_to_be32(get_slice!(4));
241+
config.channel_options.announced_channel = (get_slice!(1)[0] != 0);
242+
let channelmanager = ChannelManager::new(our_network_key,Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone(), Arc::clone(&logger), config).unwrap();
240243
let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key), watch.clone(), Arc::clone(&logger)));
241244

242245
let peers = RefCell::new([false; 256]);

src/ln/channel.rs

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use util::ser::Writeable;
2626
use util::sha2::Sha256;
2727
use util::logger::Logger;
2828
use util::errors::APIError;
29+
use util::configurations::{UserConfig,ChannelConfig};
2930

3031
use std;
3132
use std::default::Default;
@@ -277,18 +278,20 @@ const MULTI_STATE_FLAGS: u32 = (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::PeerDis
277278

278279
const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
279280

281+
280282
// TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
281283
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
282284
// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
283285
// inbound channel.
284286
pub(super) struct Channel {
287+
config : ChannelConfig,
288+
285289
user_id: u64,
286290

287291
channel_id: [u8; 32],
288292
channel_state: u32,
289293
channel_outbound: bool,
290294
secp_ctx: Secp256k1<secp256k1::All>,
291-
announce_publicly: bool,
292295
channel_value_satoshis: u64,
293296

294297
local_keys: ChannelKeys,
@@ -441,15 +444,21 @@ impl Channel {
441444
}
442445

443446
/// Returns a minimum channel reserve value **they** need to maintain
444-
///
445447
/// Guaranteed to return a value no larger than channel_value_satoshis
446448
fn get_our_channel_reserve_satoshis(channel_value_satoshis: u64) -> u64 {
447449
let (q, _) = channel_value_satoshis.overflowing_div(100);
448450
cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO
449451
}
450452

451453
fn derive_our_dust_limit_satoshis(at_open_background_feerate: u64) -> u64 {
452-
at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000 //TODO
454+
#[cfg(test)]
455+
{
456+
547
457+
}
458+
#[cfg(not(test))]
459+
{
460+
at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000 //TODO
461+
}
453462
}
454463

455464
fn derive_our_htlc_minimum_msat(_at_open_channel_feerate_per_kw: u64) -> u64 {
@@ -469,11 +478,10 @@ impl Channel {
469478
}
470479

471480
// Constructors:
472-
pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Result<Channel, APIError> {
481+
pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel, APIError> {
473482
if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
474483
return Err(APIError::APIMisuseError{err: "funding value > 2^24"});
475484
}
476-
477485
if push_msat > channel_value_satoshis * 1000 {
478486
return Err(APIError::APIMisuseError{err: "push value > channel value"});
479487
}
@@ -493,15 +501,15 @@ impl Channel {
493501
&PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key),
494502
&chan_keys.htlc_base_key,
495503
BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
496-
504+
497505
Ok(Channel {
498506
user_id: user_id,
507+
config: config.channel_options.clone(),
499508

500509
channel_id: rng::rand_u832(),
501510
channel_state: ChannelState::OurInitSent as u32,
502511
channel_outbound: true,
503512
secp_ctx: secp_ctx,
504-
announce_publicly: announce_publicly,
505513
channel_value_satoshis: channel_value_satoshis,
506514

507515
local_keys: chan_keys,
@@ -579,7 +587,8 @@ impl Channel {
579587

580588
/// Creates a new channel from a remote sides' request for one.
581589
/// Assumes chain_hash has already been checked and corresponds with what we expect!
582-
pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, ChannelError> {
590+
pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, config : &UserConfig) -> Result<Channel, ChannelError> {
591+
let mut local_config = (*config).channel_options.clone();
583592
// Check sanity of message fields:
584593
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
585594
return Err(ChannelError::Close("funding value > 2^24"));
@@ -610,23 +619,48 @@ impl Channel {
610619
if msg.max_accepted_htlcs > 483 {
611620
return Err(ChannelError::Close("max_accpted_htlcs > 483"));
612621
}
622+
//optional parameter checking
623+
// MAY fail the channel if
624+
if msg.funding_satoshis < config.channel_limits.min_funding_satoshis {
625+
return Err(ChannelError::Close("funding satoshis is less than the user specified limit"));
626+
}
627+
if msg.htlc_minimum_msat > config.channel_limits.max_htlc_minimum_msat {
628+
return Err(ChannelError::Close("htlc minimum msat is higher than the user specified limit"));
629+
}
630+
if msg.max_htlc_value_in_flight_msat < config.channel_limits.min_max_htlc_value_in_flight_msat {
631+
return Err(ChannelError::Close("max htlc value in flight msat is less than the user specified limit"));
632+
}
633+
if msg.channel_reserve_satoshis > config.channel_limits.max_channel_reserve_satoshis {
634+
return Err(ChannelError::Close("channel reserve satoshis is higher than the user specified limit"));
635+
}
636+
if msg.max_accepted_htlcs < config.channel_limits.min_max_accepted_htlcs {
637+
return Err(ChannelError::Close("max accepted htlcs is less than the user specified limit"));
638+
}
639+
if msg.dust_limit_satoshis < config.channel_limits.min_dust_limit_satoshis {
640+
println!("{:?}", msg.dust_limit_satoshis);
641+
return Err(ChannelError::Close("dust limit satoshis is less than the user specified limit"));
642+
}
643+
if msg.dust_limit_satoshis > config.channel_limits.max_dust_limit_satoshis {
644+
return Err(ChannelError::Close("dust limit satoshis is greater than the user specified limit"));
645+
}
613646

614647
// Convert things into internal flags and prep our state:
615648

616649
let their_announce = if (msg.channel_flags & 1) == 1 { true } else { false };
617-
if require_announce && !their_announce {
618-
return Err(ChannelError::Close("Peer tried to open unannounced channel, but we require public ones"));
619-
}
620-
if !allow_announce && their_announce {
621-
return Err(ChannelError::Close("Peer tried to open announced channel, but we require private ones"));
650+
if config.channel_limits.force_announced_channel_preference{
651+
if local_config.announced_channel != their_announce {
652+
return Err(ChannelError::Close("Peer tried to open channel but their announcement preference is different from ours"));
653+
}
622654
}
655+
//we either accept their preference or the preferences match
656+
local_config.announced_channel = their_announce;
623657

624658
let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
625659

626660
let our_dust_limit_satoshis = Channel::derive_our_dust_limit_satoshis(background_feerate);
627661
let our_channel_reserve_satoshis = Channel::get_our_channel_reserve_satoshis(msg.funding_satoshis);
628662
if our_channel_reserve_satoshis < our_dust_limit_satoshis {
629-
return Err(ChannelError::Close("Suitalbe channel reserve not found. aborting"));
663+
return Err(ChannelError::Close("Suitable channel reserve not found. aborting"));
630664
}
631665
if msg.channel_reserve_satoshis < our_dust_limit_satoshis {
632666
return Err(ChannelError::Close("channel_reserve_satoshis too small"));
@@ -660,12 +694,12 @@ impl Channel {
660694

661695
let mut chan = Channel {
662696
user_id: user_id,
697+
config: local_config,
663698

664699
channel_id: msg.temporary_channel_id,
665700
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
666701
channel_outbound: false,
667702
secp_ctx: secp_ctx,
668-
announce_publicly: their_announce,
669703

670704
local_keys: chan_keys,
671705
cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
@@ -1314,7 +1348,7 @@ impl Channel {
13141348

13151349
// Message handlers:
13161350

1317-
pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel) -> Result<(), ChannelError> {
1351+
pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel, config : &UserConfig) -> Result<(), ChannelError> {
13181352
// Check sanity of message fields:
13191353
if !self.channel_outbound {
13201354
return Err(ChannelError::Close("Got an accept_channel message from an inbound peer"));
@@ -1352,16 +1386,10 @@ impl Channel {
13521386
if msg.max_accepted_htlcs > 483 {
13531387
return Err(ChannelError::Close("max_accpted_htlcs > 483"));
13541388
}
1355-
1356-
// TODO: Optional additional constraints mentioned in the spec
1357-
// MAY fail the channel if
1358-
// funding_satoshi is too small
1359-
// htlc_minimum_msat too large
1360-
// max_htlc_value_in_flight_msat too small
1361-
// channel_reserve_satoshis too large
1362-
// max_accepted_htlcs too small
1363-
// dust_limit_satoshis too small
1364-
1389+
//Optional user definined limits
1390+
if msg.minimum_depth > config.channel_limits.minimum_depth {
1391+
return Err(ChannelError::Close("We consider the minimum depth to be unreasonably large"));
1392+
}
13651393
self.channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
13661394

13671395
self.their_dust_limit_satoshis = msg.dust_limit_satoshis;
@@ -2607,6 +2635,10 @@ impl Channel {
26072635
self.channel_value_satoshis
26082636
}
26092637

2638+
pub fn get_fee_proportional_millionths(&self) -> u32{
2639+
self.config.fee_proportional_millionths
2640+
}
2641+
26102642
#[cfg(test)]
26112643
pub fn get_feerate(&self) -> u64 {
26122644
self.feerate_per_kw
@@ -2648,7 +2680,7 @@ impl Channel {
26482680
}
26492681

26502682
pub fn should_announce(&self) -> bool {
2651-
self.announce_publicly
2683+
self.config.announced_channel
26522684
}
26532685

26542686
pub fn is_outbound(&self) -> bool {
@@ -2844,7 +2876,7 @@ impl Channel {
28442876
delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key),
28452877
htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key),
28462878
first_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &local_commitment_secret),
2847-
channel_flags: if self.announce_publicly {1} else {0},
2879+
channel_flags: if self.config.announced_channel {1} else {0},
28482880
shutdown_scriptpubkey: None,
28492881
}
28502882
}
@@ -2948,7 +2980,7 @@ impl Channel {
29482980
/// Note that the "channel must be funded" requirement is stricter than BOLT 7 requires - see
29492981
/// https://github.com/lightningnetwork/lightning-rfc/issues/468
29502982
pub fn get_channel_announcement(&self, our_node_id: PublicKey, chain_hash: Sha256dHash) -> Result<(msgs::UnsignedChannelAnnouncement, Signature), ChannelError> {
2951-
if !self.announce_publicly {
2983+
if !self.config.announced_channel {
29522984
return Err(ChannelError::Ignore("Channel is not available for public announcements"));
29532985
}
29542986
if self.channel_state & (ChannelState::ChannelFunded as u32) == 0 {
@@ -3318,6 +3350,7 @@ mod tests {
33183350

33193351
#[test]
33203352
fn outbound_commitment_test() {
3353+
use util::configurations::UserConfig;
33213354
// Test vectors from BOLT 3 Appendix C:
33223355
let feeest = TestFeeEstimator{fee_est: 15000};
33233356
let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
@@ -3339,7 +3372,9 @@ mod tests {
33393372
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
33403373

33413374
let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
3342-
let mut chan = Channel::new_outbound(&feeest, chan_keys, their_node_id, 10000000, 100000, false, 42, Arc::clone(&logger)).unwrap(); // Nothing uses their network key in this test
3375+
let mut config = UserConfig::new();
3376+
config.channel_options.announced_channel= false;
3377+
let mut chan = Channel::new_outbound(&feeest, chan_keys, their_node_id, 10000000, 100000, 42, Arc::clone(&logger), &config).unwrap(); // Nothing uses their network key in this test
33433378
chan.their_to_self_delay = 144;
33443379
chan.our_dust_limit_satoshis = 546;
33453380

src/ln/channelmanager.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use ln::channelmonitor::{ChannelMonitorUpdateErr, ManyChannelMonitor, CLTV_CLAIM
2727
use ln::router::{Route,RouteHop};
2828
use ln::msgs;
2929
use ln::msgs::{ChannelMessageHandler, HandleError, RAACommitmentOrder};
30+
use util::configurations::UserConfig;
3031
use util::{byte_utils, events, internal_traits, rng};
3132
use util::sha2::Sha256;
3233
use util::ser::{Readable, Writeable};
@@ -275,14 +276,13 @@ const ERR: () = "You need at least 32 bit pointers (well, usize, but we'll assum
275276
/// Implements ChannelMessageHandler, handling the multi-channel parts and passing things through
276277
/// to individual Channels.
277278
pub struct ChannelManager {
279+
default_configuration : UserConfig,
278280
genesis_hash: Sha256dHash,
279281
fee_estimator: Arc<FeeEstimator>,
280282
monitor: Arc<ManyChannelMonitor>,
281283
chain_monitor: Arc<ChainWatchInterface>,
282284
tx_broadcaster: Arc<BroadcasterInterface>,
283285

284-
announce_channels_publicly: bool,
285-
fee_proportional_millionths: u32,
286286
latest_block_height: AtomicUsize,
287287
secp_ctx: Secp256k1<secp256k1::All>,
288288

@@ -359,22 +359,19 @@ impl ChannelManager {
359359
/// This is the main "logic hub" for all channel-related actions, and implements
360360
/// ChannelMessageHandler.
361361
///
362-
/// fee_proportional_millionths is an optional fee to charge any payments routed through us.
363362
/// Non-proportional fees are fixed according to our risk using the provided fee estimator.
364363
///
365364
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
366-
pub fn new(our_network_key: SecretKey, fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
365+
pub fn new(our_network_key: SecretKey, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>, config : UserConfig) -> Result<Arc<ChannelManager>, secp256k1::Error> {
367366
let secp_ctx = Secp256k1::new();
368-
369367
let res = Arc::new(ChannelManager {
368+
default_configuration : config.clone(),
370369
genesis_hash: genesis_block(network).header.bitcoin_hash(),
371370
fee_estimator: feeest.clone(),
372371
monitor: monitor.clone(),
373372
chain_monitor,
374373
tx_broadcaster,
375374

376-
announce_channels_publicly,
377-
fee_proportional_millionths,
378375
latest_block_height: AtomicUsize::new(0), //TODO: Get an init value (generally need to replay recent chain on chain_monitor registration)
379376
secp_ctx,
380377

@@ -427,8 +424,7 @@ impl ChannelManager {
427424
Err(_) => panic!("RNG is busted!")
428425
}
429426
};
430-
431-
let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, push_msat, self.announce_channels_publicly, user_id, Arc::clone(&self.logger))?;
427+
let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, push_msat, user_id, Arc::clone(&self.logger), &self.default_configuration)?;
432428
let res = channel.get_open_channel(self.genesis_hash.clone(), &*self.fee_estimator);
433429
let mut channel_state = self.channel_state.lock().unwrap();
434430
match channel_state.by_id.entry(channel.channel_id()) {
@@ -1022,7 +1018,7 @@ impl ChannelManager {
10221018
if *amt_to_forward < chan.get_their_htlc_minimum_msat() { // amount_below_minimum
10231019
break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, Some(self.get_channel_update(chan).unwrap())));
10241020
}
1025-
let fee = amt_to_forward.checked_mul(self.fee_proportional_millionths as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan.get_our_fee_base_msat(&*self.fee_estimator) as u64) });
1021+
let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan.get_our_fee_base_msat(&*self.fee_estimator) as u64) });
10261022
if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient
10271023
break Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, Some(self.get_channel_update(chan).unwrap())));
10281024
}
@@ -1076,7 +1072,7 @@ impl ChannelManager {
10761072
cltv_expiry_delta: CLTV_EXPIRY_DELTA,
10771073
htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
10781074
fee_base_msat: chan.get_our_fee_base_msat(&*self.fee_estimator),
1079-
fee_proportional_millionths: self.fee_proportional_millionths,
1075+
fee_proportional_millionths: chan.get_fee_proportional_millionths(),
10801076
excess_data: Vec::new(),
10811077
};
10821078

@@ -1687,7 +1683,7 @@ impl ChannelManager {
16871683
}
16881684
};
16891685

1690-
let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, false, self.announce_channels_publicly, Arc::clone(&self.logger))
1686+
let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, Arc::clone(&self.logger), &self.default_configuration)
16911687
.map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id))?;
16921688
let accept_msg = channel.get_accept_channel();
16931689
channel_state.by_id.insert(channel.channel_id(), channel);
@@ -1703,7 +1699,7 @@ impl ChannelManager {
17031699
//TODO: see issue #153, need a consistent behavior on obnoxious behavior from random node
17041700
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!", msg.temporary_channel_id));
17051701
}
1706-
chan.accept_channel(&msg)
1702+
chan.accept_channel(&msg, &self.default_configuration)
17071703
.map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.temporary_channel_id))?;
17081704
(chan.get_value_satoshis(), chan.get_funding_redeemscript().to_v0_p2wsh(), chan.get_user_id())
17091705
},
@@ -3437,6 +3433,8 @@ mod tests {
34373433
}
34383434

34393435
fn create_network(node_count: usize) -> Vec<Node> {
3436+
use util::configurations::UserConfig;
3437+
34403438
let mut nodes = Vec::new();
34413439
let mut rng = thread_rng();
34423440
let secp_ctx = Secp256k1::new();
@@ -3455,7 +3453,11 @@ mod tests {
34553453
rng.fill_bytes(&mut key_slice);
34563454
SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
34573455
};
3458-
let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger)).unwrap();
3456+
let mut config = UserConfig::new();
3457+
config.channel_options.announced_channel = true;
3458+
config.channel_options.fee_proportional_millionths = 0;
3459+
config.channel_limits.force_announced_channel_preference = false;
3460+
let node = ChannelManager::new(node_id.clone(), Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger), config).unwrap();
34593461
let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), chain_monitor.clone(), Arc::clone(&logger));
34603462
nodes.push(Node { chain_monitor, tx_broadcaster, chan_monitor, node, router,
34613463
network_payment_count: payment_count.clone(),

0 commit comments

Comments
 (0)