Skip to content

Add optional user specified channel limits of bolt 2 #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion fuzz/fuzz_targets/full_stack_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use lightning::util::events::{EventsProvider,Event};
use lightning::util::reset_rng_state;
use lightning::util::logger::Logger;
use lightning::util::sha2::Sha256;
use lightning::util::configurations::UserConfig;

mod utils;

Expand Down Expand Up @@ -283,7 +284,10 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
let monitor = channelmonitor::SimpleManyChannelMonitor::new(watch.clone(), broadcast.clone());

let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone() });
let channelmanager = ChannelManager::new(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), keys_manager.clone()).unwrap();
let mut config = UserConfig::new();
config.channel_options.fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = (get_slice!(1)[0] != 0);
let channelmanager = ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone(), Arc::clone(&logger),keys_manager.clone(), config).unwrap();
let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), watch.clone(), Arc::clone(&logger)));

let peers = RefCell::new([false; 256]);
Expand Down
102 changes: 68 additions & 34 deletions src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use util::ser::{Readable, ReadableArgs, Writeable, Writer, WriterWriteAdaptor};
use util::sha2::Sha256;
use util::logger::Logger;
use util::errors::APIError;
use util::configurations::{UserConfig,ChannelConfig};

use std;
use std::default::Default;
Expand Down Expand Up @@ -225,18 +226,20 @@ const MULTI_STATE_FLAGS: u32 = (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::PeerDis

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


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

user_id: u64,

channel_id: [u8; 32],
channel_state: u32,
channel_outbound: bool,
secp_ctx: Secp256k1<secp256k1::All>,
announce_publicly: bool,
channel_value_satoshis: u64,

local_keys: ChannelKeys,
Expand Down Expand Up @@ -391,15 +394,21 @@ impl Channel {
}

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

fn derive_our_dust_limit_satoshis(at_open_background_feerate: u64) -> u64 {
at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000 //TODO
#[cfg(test)]
{
547
}
#[cfg(not(test))]
{
at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000 //TODO
}
}

fn derive_our_htlc_minimum_msat(_at_open_channel_feerate_per_kw: u64) -> u64 {
Expand All @@ -419,13 +428,12 @@ impl Channel {
}

// Constructors:
pub fn new_outbound(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Result<Channel, APIError> {
pub fn new_outbound(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel, APIError> {
let chan_keys = keys_provider.get_channel_keys(false);

if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(APIError::APIMisuseError{err: "funding value > 2^24"});
}

if push_msat > channel_value_satoshis * 1000 {
return Err(APIError::APIMisuseError{err: "push value > channel value"});
}
Expand All @@ -445,12 +453,12 @@ impl Channel {

Ok(Channel {
user_id: user_id,
config: config.channel_options.clone(),

channel_id: rng::rand_u832(),
channel_state: ChannelState::OurInitSent as u32,
channel_outbound: true,
secp_ctx: secp_ctx,
announce_publicly: announce_publicly,
channel_value_satoshis: channel_value_satoshis,

local_keys: chan_keys,
Expand Down Expand Up @@ -529,8 +537,10 @@ impl Channel {

/// Creates a new channel from a remote sides' request for one.
/// Assumes chain_hash has already been checked and corresponds with what we expect!
pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, ChannelError> {
pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, config : &UserConfig) -> Result<Channel, ChannelError> {
let chan_keys = keys_provider.get_channel_keys(true);
let mut local_config = (*config).channel_options.clone();


// Check sanity of message fields:
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
Expand Down Expand Up @@ -562,23 +572,48 @@ impl Channel {
if msg.max_accepted_htlcs > 483 {
return Err(ChannelError::Close("max_accpted_htlcs > 483"));
}
//optional parameter checking
// MAY fail the channel if
if msg.funding_satoshis < config.channel_limits.min_funding_satoshis {
return Err(ChannelError::Close("funding satoshis is less than the user specified limit"));
}
if msg.htlc_minimum_msat > config.channel_limits.max_htlc_minimum_msat {
return Err(ChannelError::Close("htlc minimum msat is higher than the user specified limit"));
}
if msg.max_htlc_value_in_flight_msat < config.channel_limits.min_max_htlc_value_in_flight_msat {
return Err(ChannelError::Close("max htlc value in flight msat is less than the user specified limit"));
}
if msg.channel_reserve_satoshis > config.channel_limits.max_channel_reserve_satoshis {
return Err(ChannelError::Close("channel reserve satoshis is higher than the user specified limit"));
}
if msg.max_accepted_htlcs < config.channel_limits.min_max_accepted_htlcs {
return Err(ChannelError::Close("max accepted htlcs is less than the user specified limit"));
}
if msg.dust_limit_satoshis < config.channel_limits.min_dust_limit_satoshis {
println!("{:?}", msg.dust_limit_satoshis);
return Err(ChannelError::Close("dust limit satoshis is less than the user specified limit"));
}
if msg.dust_limit_satoshis > config.channel_limits.max_dust_limit_satoshis {
return Err(ChannelError::Close("dust limit satoshis is greater than the user specified limit"));
}

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

let their_announce = if (msg.channel_flags & 1) == 1 { true } else { false };
if require_announce && !their_announce {
return Err(ChannelError::Close("Peer tried to open unannounced channel, but we require public ones"));
}
if !allow_announce && their_announce {
return Err(ChannelError::Close("Peer tried to open announced channel, but we require private ones"));
if config.channel_limits.force_announced_channel_preference{
if local_config.announced_channel != their_announce {
return Err(ChannelError::Close("Peer tried to open channel but their announcement preference is different from ours"));
}
}
//we either accept their preference or the preferences match
local_config.announced_channel = their_announce;

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

let our_dust_limit_satoshis = Channel::derive_our_dust_limit_satoshis(background_feerate);
let our_channel_reserve_satoshis = Channel::get_our_channel_reserve_satoshis(msg.funding_satoshis);
if our_channel_reserve_satoshis < our_dust_limit_satoshis {
return Err(ChannelError::Close("Suitalbe channel reserve not found. aborting"));
return Err(ChannelError::Close("Suitable channel reserve not found. aborting"));
}
if msg.channel_reserve_satoshis < our_dust_limit_satoshis {
return Err(ChannelError::Close("channel_reserve_satoshis too small"));
Expand Down Expand Up @@ -609,12 +644,12 @@ impl Channel {

let mut chan = Channel {
user_id: user_id,
config: local_config,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
channel_outbound: false,
secp_ctx: secp_ctx,
announce_publicly: their_announce,

local_keys: chan_keys,
shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
Expand Down Expand Up @@ -1264,7 +1299,7 @@ impl Channel {

// Message handlers:

pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel) -> Result<(), ChannelError> {
pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel, config : &UserConfig) -> Result<(), ChannelError> {
// Check sanity of message fields:
if !self.channel_outbound {
return Err(ChannelError::Close("Got an accept_channel message from an inbound peer"));
Expand Down Expand Up @@ -1302,16 +1337,10 @@ impl Channel {
if msg.max_accepted_htlcs > 483 {
return Err(ChannelError::Close("max_accpted_htlcs > 483"));
}

// TODO: Optional additional constraints mentioned in the spec
// MAY fail the channel if
// funding_satoshi is too small
// htlc_minimum_msat too large
// max_htlc_value_in_flight_msat too small
// channel_reserve_satoshis too large
// max_accepted_htlcs too small
// dust_limit_satoshis too small

//Optional user definined limits
if msg.minimum_depth > config.channel_limits.minimum_depth {
return Err(ChannelError::Close("We consider the minimum depth to be unreasonably large"));
}
self.channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);

self.their_dust_limit_satoshis = msg.dust_limit_satoshis;
Expand Down Expand Up @@ -2575,6 +2604,10 @@ impl Channel {
self.channel_value_satoshis
}

pub fn get_fee_proportional_millionths(&self) -> u32{
self.config.fee_proportional_millionths
}

#[cfg(test)]
pub fn get_feerate(&self) -> u64 {
self.feerate_per_kw
Expand Down Expand Up @@ -2628,7 +2661,7 @@ impl Channel {
}

pub fn should_announce(&self) -> bool {
self.announce_publicly
self.config.announced_channel
}

pub fn is_outbound(&self) -> bool {
Expand Down Expand Up @@ -2827,7 +2860,7 @@ impl Channel {
delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key),
htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key),
first_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &local_commitment_secret),
channel_flags: if self.announce_publicly {1} else {0},
channel_flags: if self.config.announced_channel {1} else {0},
shutdown_scriptpubkey: None,
}
}
Expand Down Expand Up @@ -2931,7 +2964,7 @@ impl Channel {
/// Note that the "channel must be funded" requirement is stricter than BOLT 7 requires - see
/// https://github.com/lightningnetwork/lightning-rfc/issues/468
pub fn get_channel_announcement(&self, our_node_id: PublicKey, chain_hash: Sha256dHash) -> Result<(msgs::UnsignedChannelAnnouncement, Signature), ChannelError> {
if !self.announce_publicly {
if !self.config.announced_channel {
return Err(ChannelError::Ignore("Channel is not available for public announcements"));
}
if self.channel_state & (ChannelState::ChannelFunded as u32) == 0 {
Expand Down Expand Up @@ -3307,11 +3340,11 @@ impl Writeable for Channel {
writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?;

self.user_id.write(writer)?;
self.config.write(writer)?;

self.channel_id.write(writer)?;
(self.channel_state | ChannelState::PeerDisconnected as u32).write(writer)?;
self.channel_outbound.write(writer)?;
self.announce_publicly.write(writer)?;
self.channel_value_satoshis.write(writer)?;

self.local_keys.write(writer)?;
Expand Down Expand Up @@ -3509,11 +3542,10 @@ impl<R : ::std::io::Read> ReadableArgs<R, Arc<Logger>> for Channel {
}

let user_id = Readable::read(reader)?;

let config : ChannelConfig = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_outbound = Readable::read(reader)?;
let announce_publicly = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;

let local_keys = Readable::read(reader)?;
Expand Down Expand Up @@ -3676,12 +3708,11 @@ impl<R : ::std::io::Read> ReadableArgs<R, Arc<Logger>> for Channel {

Ok(Channel {
user_id,

config,
channel_id,
channel_state,
channel_outbound,
secp_ctx: Secp256k1::new(),
announce_publicly,
channel_value_satoshis,

local_keys,
Expand Down Expand Up @@ -3813,6 +3844,7 @@ mod tests {

#[test]
fn outbound_commitment_test() {
use util::configurations::UserConfig;
// Test vectors from BOLT 3 Appendix C:
let feeest = TestFeeEstimator{fee_est: 15000};
let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
Expand All @@ -3833,7 +3865,9 @@ mod tests {
let keys_provider: Arc<KeysInterface> = Arc::new(Keys { chan_keys });

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

Expand Down
Loading