Skip to content

Added tests to check the bolt 2 specs for open_channel (Sending Node) #262

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: 6 additions & 0 deletions fuzz/fuzz_targets/full_stack_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ impl KeysInterface for KeyProvider {
fill_bytes(&mut session_key);
SecretKey::from_slice(&session_key).unwrap()
}

fn get_channel_id(&self) -> [u8; 32] {
let mut channel_id = [0; 32];
fill_bytes(&mut channel_id);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old version actually has u64s byte-swapped.

channel_id
}
}

#[inline]
Expand Down
21 changes: 21 additions & 0 deletions src/chain/keysinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ pub trait KeysInterface: Send + Sync {
fn get_channel_keys(&self, inbound: bool) -> ChannelKeys;
/// Get a secret for construting an onion packet
fn get_session_key(&self) -> SecretKey;
/// Get a unique channel id
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit sparse. Specifically, should probably mention that we will use the funding txid once it exists at least.

fn get_channel_id(&self) -> [u8; 32];
}

/// Set of lightning keys needed to operate a channel as described in BOLT 3
Expand Down Expand Up @@ -124,6 +126,8 @@ pub struct KeysManager {
channel_child_index: AtomicUsize,
session_master_key: ExtendedPrivKey,
session_child_index: AtomicUsize,
channel_id_master_key: ExtendedPrivKey,
channel_id_child_index: AtomicUsize,

logger: Arc<Logger>,
}
Expand Down Expand Up @@ -151,6 +155,7 @@ impl KeysManager {
};
let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3)).expect("Your RNG is busted");
let session_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4)).expect("Your RNG is busted");
let channel_id_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5)).expect("Your RNG is busted");
KeysManager {
secp_ctx,
node_secret,
Expand All @@ -160,6 +165,8 @@ impl KeysManager {
channel_child_index: AtomicUsize::new(0),
session_master_key,
session_child_index: AtomicUsize::new(0),
channel_id_master_key,
channel_id_child_index: AtomicUsize::new(0),

logger,
}
Expand Down Expand Up @@ -246,4 +253,18 @@ impl KeysInterface for KeysManager {
sha.input(&child_privkey.secret_key[..]);
SecretKey::from_slice(&Sha256::from_engine(sha).into_inner()).expect("Your RNG is busted")
}

fn get_channel_id(&self) -> [u8; 32] {
let mut sha = Sha256::engine();

let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
sha.input(&byte_utils::be32_to_array(now.subsec_nanos()));
sha.input(&byte_utils::be64_to_array(now.as_secs()));

let child_ix = self.channel_id_child_index.fetch_add(1, Ordering::AcqRel);
let child_privkey = self.channel_id_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32)).expect("Your RNG is busted");
sha.input(&child_privkey.secret_key[..]);

(Sha256::from_engine(sha).into_inner())
}
}
8 changes: 6 additions & 2 deletions src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::transaction::OutPoint;
use chain::keysinterface::{ChannelKeys, KeysInterface};
use util::{transaction_utils,rng};
use util::transaction_utils;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, WriterWriteAdaptor};
use util::logger::Logger;
use util::errors::APIError;
Expand Down Expand Up @@ -350,7 +350,10 @@ pub const OUR_MAX_HTLCS: u16 = 50; //TODO
const UNCONF_THRESHOLD: u32 = 6;
/// The amount of time we require our counterparty wait to claim their money (ie time between when
/// we, or our watchtower, must check for them having broadcast a theft transaction).
#[cfg(not(test))]
const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
#[cfg(test)]
pub const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
/// The amount of time we're willing to wait to claim money back to us
const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14;
/// Exposing these two constants for use in test in ChannelMonitor
Expand Down Expand Up @@ -444,7 +447,7 @@ impl Channel {
user_id: user_id,
config: config.channel_options.clone(),

channel_id: rng::rand_u832(),
channel_id: keys_provider.get_channel_id(),
channel_state: ChannelState::OurInitSent as u32,
channel_outbound: true,
secp_ctx: secp_ctx,
Expand Down Expand Up @@ -3958,6 +3961,7 @@ mod tests {

fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys { self.chan_keys.clone() }
fn get_session_key(&self) -> SecretKey { panic!(); }
fn get_channel_id(&self) -> [u8; 32] { [0; 32] }
}

#[test]
Expand Down
64 changes: 63 additions & 1 deletion src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use chain::transaction::OutPoint;
use chain::chaininterface::{ChainListener, ChainWatchInterface};
use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
use chain::keysinterface;
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, BREAKDOWN_TIMEOUT};
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash};
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor};
use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT};
Expand Down Expand Up @@ -6716,6 +6716,68 @@ fn test_onion_failure() {
}, ||{}, true, Some(21), None);
}

#[test]
#[should_panic]
fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on its own as we are catching a panic
let nodes = create_network(2);
//Force duplicate channel ids
for node in nodes.iter() {
*node.keys_manager.override_channel_id_priv.lock().unwrap() = Some([0; 32]);
}

// BOLT #2 spec: Sending node must ensure temporary_channel_id is unique from any other channel ID with the same peer.
let channel_value_satoshis=10000;
let push_msat=10001;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).unwrap();
let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &node0_to_1_send_open_channel).unwrap();

//Create a second channel with a channel_id collision
assert!(nodes[0].node.create_channel(nodes[0].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_err());
}

#[test]
fn bolt2_open_channel_sending_node_checks_part2() {
let nodes = create_network(2);

// BOLT #2 spec: Sending node must set funding_satoshis to less than 2^24 satoshis
let channel_value_satoshis=2^24;
let push_msat=10001;
assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_err());

// BOLT #2 spec: Sending node must set push_msat to equal or less than 1000 * funding_satoshis
let channel_value_satoshis=10000;
// Test when push_msat is equal to 1000 * funding_satoshis.
let push_msat=1000*channel_value_satoshis+1;
assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_err());

// BOLT #2 spec: Sending node must set set channel_reserve_satoshis greater than or equal to dust_limit_satoshis
let channel_value_satoshis=10000;
let push_msat=10001;
assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_ok()); //Create a valid channel
let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
assert!(node0_to_1_send_open_channel.channel_reserve_satoshis>=node0_to_1_send_open_channel.dust_limit_satoshis);

// BOLT #2 spec: Sending node must set undefined bits in channel_flags to 0
// Only the least-significant bit of channel_flags is currently defined resulting in channel_flags only having one of two possible states 0 or 1
assert!(node0_to_1_send_open_channel.channel_flags<=1);

// BOLT #2 spec: Sending node should set to_self_delay sufficient to ensure the sender can irreversibly spend a commitment transaction output, in case of misbehaviour by the receiver.
assert!(BREAKDOWN_TIMEOUT>0);
assert!(node0_to_1_send_open_channel.to_self_delay==BREAKDOWN_TIMEOUT);

// BOLT #2 spec: Sending node must ensure the chain_hash value identifies the chain it wishes to open the channel within.
let chain_hash=genesis_block(Network::Testnet).header.bitcoin_hash();
assert_eq!(node0_to_1_send_open_channel.chain_hash,chain_hash);

// BOLT #2 spec: Sending node must set funding_pubkey, revocation_basepoint, htlc_basepoint, payment_basepoint, and delayed_payment_basepoint to valid DER-encoded, compressed, secp256k1 pubkeys.
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.funding_pubkey.serialize()).is_ok());
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.revocation_basepoint.serialize()).is_ok());
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.htlc_basepoint.serialize()).is_ok());
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.payment_basepoint.serialize()).is_ok());
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.delayed_payment_basepoint.serialize()).is_ok());
}

// BOLT 2 Requirements for the Sender when constructing and sending an update_add_htlc message.
// BOLT 2 Requirement: MUST NOT offer amount_msat it cannot pay for in the remote commitment transaction at the current feerate_per_kw (see "Updating Fees") while maintaining its channel reserve.
//TODO: I don't believe this is explicitly enforced when sending an HTLC but as the Fee aspect of the BOLT specs is in flux leaving this as a TODO.
Expand Down
9 changes: 9 additions & 0 deletions src/util/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ impl Logger for TestLogger {
pub struct TestKeysInterface {
backing: keysinterface::KeysManager,
pub override_session_priv: Mutex<Option<SecretKey>>,
pub override_channel_id_priv: Mutex<Option<[u8; 32]>>,
}

impl keysinterface::KeysInterface for TestKeysInterface {
Expand All @@ -229,13 +230,21 @@ impl keysinterface::KeysInterface for TestKeysInterface {
None => self.backing.get_session_key()
}
}

fn get_channel_id(&self) -> [u8; 32] {
match *self.override_channel_id_priv.lock().unwrap() {
Some(key) => key.clone(),
None => self.backing.get_channel_id()
}
}
}

impl TestKeysInterface {
pub fn new(seed: &[u8; 32], network: Network, logger: Arc<Logger>) -> Self {
Self {
backing: keysinterface::KeysManager::new(seed, network, logger),
override_session_priv: Mutex::new(None),
override_channel_id_priv: Mutex::new(None),
}
}
}