Added tests to check the bolt 2 specs for Sending Node Channel 2019-01-262-redux
authorYuko Roodt <neonknight@tari.com>
Fri, 30 Nov 2018 09:51:37 +0000 (11:51 +0200)
committerMatt Corallo <git@bluematt.me>
Wed, 23 Jan 2019 19:54:10 +0000 (14:54 -0500)
fuzz/fuzz_targets/full_stack_target.rs
src/chain/keysinterface.rs
src/ln/channel.rs
src/ln/functional_tests.rs
src/util/rng.rs
src/util/test_utils.rs

index 067c73d217e2517c4e2f43c03aaad92895d898d7..9930a44d2558cf54922fa8c1878bcf6a5965effb 100644 (file)
@@ -281,6 +281,29 @@ 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);
+               for i in 0..4 {
+                       // byteswap the u64s in channel_id to make it distinct from get_session_key (and match
+                       // old code that wrote out different endianness).
+                       let mut t;
+                       t = channel_id[i*8 + 0];
+                       channel_id[i*8 + 0] = channel_id[i*8 + 7];
+                       channel_id[i*8 + 7] = t;
+                       t = channel_id[i*8 + 1];
+                       channel_id[i*8 + 1] = channel_id[i*8 + 6];
+                       channel_id[i*8 + 6] = t;
+                       t = channel_id[i*8 + 2];
+                       channel_id[i*8 + 2] = channel_id[i*8 + 5];
+                       channel_id[i*8 + 5] = t;
+                       t = channel_id[i*8 + 3];
+                       channel_id[i*8 + 3] = channel_id[i*8 + 4];
+                       channel_id[i*8 + 4] = t;
+               }
+               channel_id
+       }
 }
 
 #[inline]
index 53191faf2c9162e75db69661dec3aec483c76a50..9369d3c35063486a405a202c18c3b0426f93b5ac 100644 (file)
@@ -80,6 +80,10 @@ 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 temporary channel id. Channels will be referred to by this until the funding
+       /// transaction is created, at which point they will use the outpoint in the funding
+       /// transaction.
+       fn get_channel_id(&self) -> [u8; 32];
 }
 
 /// Set of lightning keys needed to operate a channel as described in BOLT 3
@@ -124,6 +128,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>,
 }
@@ -151,6 +157,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,
@@ -160,6 +167,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,
                                }
@@ -246,4 +255,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())
+       }
 }
index 10b0725cdf2bc75ee2907ee548f3bd123a2a3006..326df90dcb5127c9d58d6b0e6a00ccc9d2e6355c 100644 (file)
@@ -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;
@@ -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
@@ -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,
@@ -3950,6 +3953,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]
index 6a2b6d3db712f32ab64e02172ccc6c4937fa9d12..b6463bf32d9b8e1d36b1b90d57188bc4916476c3 100644 (file)
@@ -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};
@@ -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.
index ae50154d95dea23b29d25c36aeff13372b4b101a..63fbc99b52a847ea28e23e3e33dfc14916445058 100644 (file)
@@ -7,12 +7,6 @@ mod real_rng {
                rng.fill_bytes(data);
        }
 
-       pub fn rand_u832() -> [u8; 32] {
-               let mut res = [0; 32];
-               fill_bytes(&mut res);
-               res
-       }
-
        pub fn rand_f32() -> f32 {
                let mut rng = thread_rng();
                rng.next_f32()
@@ -37,17 +31,6 @@ mod fuzzy_rng {
                data[off..].copy_from_slice(&byte_utils::be64_to_array(rng)[0..rem]);
        }
 
-       pub fn rand_u832() -> [u8; 32] {
-               let rng = unsafe { RNG_ITER += 1; RNG_ITER - 1 };
-               let mut res = [0; 32];
-               let data = byte_utils::le64_to_array(rng);
-               res[8*0..8*1].copy_from_slice(&data);
-               res[8*1..8*2].copy_from_slice(&data);
-               res[8*2..8*3].copy_from_slice(&data);
-               res[8*3..8*4].copy_from_slice(&data);
-               res
-       }
-
        pub fn rand_f32() -> f32 {
                let rng = unsafe { RNG_ITER += 1; RNG_ITER - 1 };
                f64::from_bits(rng) as f32
index b889e254eb47557df5d1055f9fb2b86811d30654..4360c5701c40e93927eab81bcdc3a4963236a34e 100644 (file)
@@ -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 {
@@ -229,6 +230,13 @@ 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 {
@@ -236,6 +244,7 @@ impl TestKeysInterface {
                Self {
                        backing: keysinterface::KeysManager::new(seed, network, logger),
                        override_session_priv: Mutex::new(None),
+                       override_channel_id_priv: Mutex::new(None),
                }
        }
 }