Skip to content

Commit 4d77e9d

Browse files
Yuko RoodtTheBlueMatt
Yuko Roodt
authored andcommitted
Added tests to check the bolt 2 specs for Sending Node Channel
1 parent 7a77c9f commit 4d77e9d

File tree

6 files changed

+124
-20
lines changed

6 files changed

+124
-20
lines changed

fuzz/fuzz_targets/full_stack_target.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,29 @@ impl KeysInterface for KeyProvider {
281281
fill_bytes(&mut session_key);
282282
SecretKey::from_slice(&session_key).unwrap()
283283
}
284+
285+
fn get_channel_id(&self) -> [u8; 32] {
286+
let mut channel_id = [0; 32];
287+
fill_bytes(&mut channel_id);
288+
for i in 0..4 {
289+
// byteswap the u64s in channel_id to make it distinct from get_session_key (and match
290+
// old code that wrote out different endianness).
291+
let mut t;
292+
t = channel_id[i*8 + 0];
293+
channel_id[i*8 + 0] = channel_id[i*8 + 7];
294+
channel_id[i*8 + 7] = t;
295+
t = channel_id[i*8 + 1];
296+
channel_id[i*8 + 1] = channel_id[i*8 + 6];
297+
channel_id[i*8 + 6] = t;
298+
t = channel_id[i*8 + 2];
299+
channel_id[i*8 + 2] = channel_id[i*8 + 5];
300+
channel_id[i*8 + 5] = t;
301+
t = channel_id[i*8 + 3];
302+
channel_id[i*8 + 3] = channel_id[i*8 + 4];
303+
channel_id[i*8 + 4] = t;
304+
}
305+
channel_id
306+
}
284307
}
285308

286309
#[inline]

src/chain/keysinterface.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ pub trait KeysInterface: Send + Sync {
8080
fn get_channel_keys(&self, inbound: bool) -> ChannelKeys;
8181
/// Get a secret for construting an onion packet
8282
fn get_session_key(&self) -> SecretKey;
83+
/// Get a unique temporary channel id. Channels will be referred to by this until the funding
84+
/// transaction is created, at which point they will use the outpoint in the funding
85+
/// transaction.
86+
fn get_channel_id(&self) -> [u8; 32];
8387
}
8488

8589
/// Set of lightning keys needed to operate a channel as described in BOLT 3
@@ -124,6 +128,8 @@ pub struct KeysManager {
124128
channel_child_index: AtomicUsize,
125129
session_master_key: ExtendedPrivKey,
126130
session_child_index: AtomicUsize,
131+
channel_id_master_key: ExtendedPrivKey,
132+
channel_id_child_index: AtomicUsize,
127133

128134
logger: Arc<Logger>,
129135
}
@@ -151,6 +157,7 @@ impl KeysManager {
151157
};
152158
let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3)).expect("Your RNG is busted");
153159
let session_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4)).expect("Your RNG is busted");
160+
let channel_id_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5)).expect("Your RNG is busted");
154161
KeysManager {
155162
secp_ctx,
156163
node_secret,
@@ -160,6 +167,8 @@ impl KeysManager {
160167
channel_child_index: AtomicUsize::new(0),
161168
session_master_key,
162169
session_child_index: AtomicUsize::new(0),
170+
channel_id_master_key,
171+
channel_id_child_index: AtomicUsize::new(0),
163172

164173
logger,
165174
}
@@ -246,4 +255,18 @@ impl KeysInterface for KeysManager {
246255
sha.input(&child_privkey.secret_key[..]);
247256
SecretKey::from_slice(&Sha256::from_engine(sha).into_inner()).expect("Your RNG is busted")
248257
}
258+
259+
fn get_channel_id(&self) -> [u8; 32] {
260+
let mut sha = Sha256::engine();
261+
262+
let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
263+
sha.input(&byte_utils::be32_to_array(now.subsec_nanos()));
264+
sha.input(&byte_utils::be64_to_array(now.as_secs()));
265+
266+
let child_ix = self.channel_id_child_index.fetch_add(1, Ordering::AcqRel);
267+
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");
268+
sha.input(&child_privkey.secret_key[..]);
269+
270+
(Sha256::from_engine(sha).into_inner())
271+
}
249272
}

src/ln/channel.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ln::chan_utils;
2323
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
2424
use chain::transaction::OutPoint;
2525
use chain::keysinterface::{ChannelKeys, KeysInterface};
26-
use util::{transaction_utils,rng};
26+
use util::transaction_utils;
2727
use util::ser::{Readable, ReadableArgs, Writeable, Writer, WriterWriteAdaptor};
2828
use util::logger::Logger;
2929
use util::errors::APIError;
@@ -350,7 +350,10 @@ pub const OUR_MAX_HTLCS: u16 = 50; //TODO
350350
const UNCONF_THRESHOLD: u32 = 6;
351351
/// The amount of time we require our counterparty wait to claim their money (ie time between when
352352
/// we, or our watchtower, must check for them having broadcast a theft transaction).
353+
#[cfg(not(test))]
353354
const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
355+
#[cfg(test)]
356+
pub const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
354357
/// The amount of time we're willing to wait to claim money back to us
355358
const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14;
356359
/// Exposing these two constants for use in test in ChannelMonitor
@@ -444,7 +447,7 @@ impl Channel {
444447
user_id: user_id,
445448
config: config.channel_options.clone(),
446449

447-
channel_id: rng::rand_u832(),
450+
channel_id: keys_provider.get_channel_id(),
448451
channel_state: ChannelState::OurInitSent as u32,
449452
channel_outbound: true,
450453
secp_ctx: secp_ctx,
@@ -3950,6 +3953,7 @@ mod tests {
39503953

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

39553959
#[test]

src/ln/functional_tests.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use chain::transaction::OutPoint;
77
use chain::chaininterface::{ChainListener, ChainWatchInterface};
88
use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
99
use chain::keysinterface;
10-
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
10+
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, BREAKDOWN_TIMEOUT};
1111
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash};
1212
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor};
1313
use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT};
@@ -6716,6 +6716,68 @@ fn test_onion_failure() {
67166716
}, ||{}, true, Some(21), None);
67176717
}
67186718

6719+
#[test]
6720+
#[should_panic]
6721+
fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on its own as we are catching a panic
6722+
let nodes = create_network(2);
6723+
//Force duplicate channel ids
6724+
for node in nodes.iter() {
6725+
*node.keys_manager.override_channel_id_priv.lock().unwrap() = Some([0; 32]);
6726+
}
6727+
6728+
// BOLT #2 spec: Sending node must ensure temporary_channel_id is unique from any other channel ID with the same peer.
6729+
let channel_value_satoshis=10000;
6730+
let push_msat=10001;
6731+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).unwrap();
6732+
let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
6733+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &node0_to_1_send_open_channel).unwrap();
6734+
6735+
//Create a second channel with a channel_id collision
6736+
assert!(nodes[0].node.create_channel(nodes[0].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_err());
6737+
}
6738+
6739+
#[test]
6740+
fn bolt2_open_channel_sending_node_checks_part2() {
6741+
let nodes = create_network(2);
6742+
6743+
// BOLT #2 spec: Sending node must set funding_satoshis to less than 2^24 satoshis
6744+
let channel_value_satoshis=2^24;
6745+
let push_msat=10001;
6746+
assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_err());
6747+
6748+
// BOLT #2 spec: Sending node must set push_msat to equal or less than 1000 * funding_satoshis
6749+
let channel_value_satoshis=10000;
6750+
// Test when push_msat is equal to 1000 * funding_satoshis.
6751+
let push_msat=1000*channel_value_satoshis+1;
6752+
assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42).is_err());
6753+
6754+
// BOLT #2 spec: Sending node must set set channel_reserve_satoshis greater than or equal to dust_limit_satoshis
6755+
let channel_value_satoshis=10000;
6756+
let push_msat=10001;
6757+
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
6758+
let node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
6759+
assert!(node0_to_1_send_open_channel.channel_reserve_satoshis>=node0_to_1_send_open_channel.dust_limit_satoshis);
6760+
6761+
// BOLT #2 spec: Sending node must set undefined bits in channel_flags to 0
6762+
// 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
6763+
assert!(node0_to_1_send_open_channel.channel_flags<=1);
6764+
6765+
// 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.
6766+
assert!(BREAKDOWN_TIMEOUT>0);
6767+
assert!(node0_to_1_send_open_channel.to_self_delay==BREAKDOWN_TIMEOUT);
6768+
6769+
// BOLT #2 spec: Sending node must ensure the chain_hash value identifies the chain it wishes to open the channel within.
6770+
let chain_hash=genesis_block(Network::Testnet).header.bitcoin_hash();
6771+
assert_eq!(node0_to_1_send_open_channel.chain_hash,chain_hash);
6772+
6773+
// 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.
6774+
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.funding_pubkey.serialize()).is_ok());
6775+
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.revocation_basepoint.serialize()).is_ok());
6776+
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.htlc_basepoint.serialize()).is_ok());
6777+
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.payment_basepoint.serialize()).is_ok());
6778+
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.delayed_payment_basepoint.serialize()).is_ok());
6779+
}
6780+
67196781
// BOLT 2 Requirements for the Sender when constructing and sending an update_add_htlc message.
67206782
// 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.
67216783
//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.

src/util/rng.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ mod real_rng {
77
rng.fill_bytes(data);
88
}
99

10-
pub fn rand_u832() -> [u8; 32] {
11-
let mut res = [0; 32];
12-
fill_bytes(&mut res);
13-
res
14-
}
15-
1610
pub fn rand_f32() -> f32 {
1711
let mut rng = thread_rng();
1812
rng.next_f32()
@@ -37,17 +31,6 @@ mod fuzzy_rng {
3731
data[off..].copy_from_slice(&byte_utils::be64_to_array(rng)[0..rem]);
3832
}
3933

40-
pub fn rand_u832() -> [u8; 32] {
41-
let rng = unsafe { RNG_ITER += 1; RNG_ITER - 1 };
42-
let mut res = [0; 32];
43-
let data = byte_utils::le64_to_array(rng);
44-
res[8*0..8*1].copy_from_slice(&data);
45-
res[8*1..8*2].copy_from_slice(&data);
46-
res[8*2..8*3].copy_from_slice(&data);
47-
res[8*3..8*4].copy_from_slice(&data);
48-
res
49-
}
50-
5134
pub fn rand_f32() -> f32 {
5235
let rng = unsafe { RNG_ITER += 1; RNG_ITER - 1 };
5336
f64::from_bits(rng) as f32

src/util/test_utils.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ impl Logger for TestLogger {
215215
pub struct TestKeysInterface {
216216
backing: keysinterface::KeysManager,
217217
pub override_session_priv: Mutex<Option<SecretKey>>,
218+
pub override_channel_id_priv: Mutex<Option<[u8; 32]>>,
218219
}
219220

220221
impl keysinterface::KeysInterface for TestKeysInterface {
@@ -229,13 +230,21 @@ impl keysinterface::KeysInterface for TestKeysInterface {
229230
None => self.backing.get_session_key()
230231
}
231232
}
233+
234+
fn get_channel_id(&self) -> [u8; 32] {
235+
match *self.override_channel_id_priv.lock().unwrap() {
236+
Some(key) => key.clone(),
237+
None => self.backing.get_channel_id()
238+
}
239+
}
232240
}
233241

234242
impl TestKeysInterface {
235243
pub fn new(seed: &[u8; 32], network: Network, logger: Arc<Logger>) -> Self {
236244
Self {
237245
backing: keysinterface::KeysManager::new(seed, network, logger),
238246
override_session_priv: Mutex::new(None),
247+
override_channel_id_priv: Mutex::new(None),
239248
}
240249
}
241250
}

0 commit comments

Comments
 (0)