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]
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
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>,
}
};
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,
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,
}
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())
+ }
}
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;
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
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,
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]
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};
}, ||{}, 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.
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()
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
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 {
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 {
Self {
backing: keysinterface::KeysManager::new(seed, network, logger),
override_session_priv: Mutex::new(None),
+ override_channel_id_priv: Mutex::new(None),
}
}
}