Skip to content

Commit cd9d680

Browse files
authored
Merge pull request #145 from TheBlueMatt/2018-09-134-rebased
#134 rebased
2 parents 5fb2cc4 + 6dfec32 commit cd9d680

File tree

7 files changed

+214
-24
lines changed

7 files changed

+214
-24
lines changed

fuzz/fuzz_targets/full_stack_target.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,12 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
232232
Err(_) => return,
233233
};
234234

235-
let watch = Arc::new(ChainWatchInterfaceUtil::new(Arc::clone(&logger)));
235+
let watch = Arc::new(ChainWatchInterfaceUtil::new(Network::Bitcoin, Arc::clone(&logger)));
236236
let broadcast = Arc::new(TestBroadcaster{});
237237
let monitor = channelmonitor::SimpleManyChannelMonitor::new(watch.clone(), broadcast.clone());
238238

239239
let channelmanager = ChannelManager::new(our_network_key, 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)).unwrap();
240-
let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key), Arc::clone(&logger)));
240+
let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key), watch.clone(), Arc::clone(&logger)));
241241

242242
let peers = RefCell::new([false; 256]);
243243
let mut loss_detector = MoneyLossDetector::new(&peers, channelmanager.clone(), monitor.clone(), PeerManager::new(MessageHandler {

fuzz/fuzz_targets/router_target.rs

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ extern crate bitcoin;
22
extern crate lightning;
33
extern crate secp256k1;
44

5+
use bitcoin::util::hash::Sha256dHash;
6+
use bitcoin::blockdata::script::{Script, Builder};
7+
use bitcoin::blockdata::opcodes;
8+
9+
use lightning::chain::chaininterface::{ChainError,ChainWatchInterface, ChainListener};
510
use lightning::ln::channelmanager::ChannelDetails;
611
use lightning::ln::msgs;
712
use lightning::ln::msgs::{MsgDecodable, RoutingMessageHandler};
@@ -16,7 +21,8 @@ mod utils;
1621

1722
use utils::test_logger;
1823

19-
use std::sync::Arc;
24+
use std::sync::{Weak, Arc};
25+
use std::sync::atomic::{AtomicUsize, Ordering};
2026

2127
#[inline]
2228
pub fn slice_to_be16(v: &[u8]) -> u16 {
@@ -44,27 +50,71 @@ pub fn slice_to_be64(v: &[u8]) -> u64 {
4450
((v[7] as u64) << 8*0)
4551
}
4652

53+
54+
struct InputData {
55+
data: Vec<u8>,
56+
read_pos: AtomicUsize,
57+
}
58+
impl InputData {
59+
fn get_slice(&self, len: usize) -> Option<&[u8]> {
60+
let old_pos = self.read_pos.fetch_add(len, Ordering::AcqRel);
61+
if self.data.len() < old_pos + len {
62+
return None;
63+
}
64+
Some(&self.data[old_pos..old_pos + len])
65+
}
66+
fn get_slice_nonadvancing(&self, len: usize) -> Option<&[u8]> {
67+
let old_pos = self.read_pos.load(Ordering::Acquire);
68+
if self.data.len() < old_pos + len {
69+
return None;
70+
}
71+
Some(&self.data[old_pos..old_pos + len])
72+
}
73+
}
74+
75+
struct DummyChainWatcher {
76+
input: Arc<InputData>,
77+
}
78+
79+
impl ChainWatchInterface for DummyChainWatcher {
80+
fn install_watch_script(&self, _script_pub_key: &Script) { }
81+
fn install_watch_outpoint(&self, _outpoint: (Sha256dHash, u32), _out_script: &Script) { }
82+
fn watch_all_txn(&self) { }
83+
fn register_listener(&self, _listener: Weak<ChainListener>) { }
84+
85+
fn get_chain_utxo(&self, _genesis_hash: Sha256dHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> {
86+
match self.input.get_slice(2) {
87+
Some(&[0, _]) => Err(ChainError::NotSupported),
88+
Some(&[1, _]) => Err(ChainError::NotWatched),
89+
Some(&[2, _]) => Err(ChainError::UnknownTx),
90+
Some(&[_, x]) => Ok((Builder::new().push_int(x as i64).into_script().to_v0_p2wsh(), 0)),
91+
None => Err(ChainError::UnknownTx),
92+
_ => unreachable!(),
93+
}
94+
}
95+
}
96+
4797
#[inline]
4898
pub fn do_test(data: &[u8]) {
4999
reset_rng_state();
50100

51-
let mut read_pos = 0;
101+
let input = Arc::new(InputData {
102+
data: data.to_vec(),
103+
read_pos: AtomicUsize::new(0),
104+
});
52105
macro_rules! get_slice_nonadvancing {
53106
($len: expr) => {
54-
{
55-
if data.len() < read_pos + $len as usize {
56-
return;
57-
}
58-
&data[read_pos..read_pos + $len as usize]
107+
match input.get_slice_nonadvancing($len as usize) {
108+
Some(slice) => slice,
109+
None => return,
59110
}
60111
}
61112
}
62113
macro_rules! get_slice {
63114
($len: expr) => {
64-
{
65-
let res = get_slice_nonadvancing!($len);
66-
read_pos += $len;
67-
res
115+
match input.get_slice($len as usize) {
116+
Some(slice) => slice,
117+
None => return,
68118
}
69119
}
70120
}
@@ -107,9 +157,12 @@ pub fn do_test(data: &[u8]) {
107157
}
108158

109159
let logger: Arc<Logger> = Arc::new(test_logger::TestLogger{});
160+
let chain_monitor = Arc::new(DummyChainWatcher {
161+
input: Arc::clone(&input),
162+
});
110163

111164
let our_pubkey = get_pubkey!();
112-
let router = Router::new(our_pubkey.clone(), Arc::clone(&logger));
165+
let router = Router::new(our_pubkey.clone(), chain_monitor, Arc::clone(&logger));
113166

114167
loop {
115168
match get_slice!(1)[0] {

src/chain/chaininterface.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
use bitcoin::blockdata::block::{Block, BlockHeader};
22
use bitcoin::blockdata::transaction::Transaction;
33
use bitcoin::blockdata::script::Script;
4+
use bitcoin::blockdata::constants::genesis_block;
45
use bitcoin::util::hash::Sha256dHash;
6+
use bitcoin::network::constants::Network;
7+
use bitcoin::network::serialize::BitcoinHash;
58
use util::logger::Logger;
69
use std::sync::{Mutex,Weak,MutexGuard,Arc};
710
use std::sync::atomic::{AtomicUsize, Ordering};
811

12+
/// Used to give chain error details upstream
13+
pub enum ChainError {
14+
/// Client doesn't support UTXO lookup (but the chain hash matches our genesis block hash)
15+
NotSupported,
16+
/// Chain isn't the one watched
17+
NotWatched,
18+
/// Tx doesn't exist or is unconfirmed
19+
UnknownTx,
20+
}
21+
922
/// An interface to request notification of certain scripts as they appear the
1023
/// chain.
1124
/// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
@@ -24,6 +37,12 @@ pub trait ChainWatchInterface: Sync + Send {
2437

2538
fn register_listener(&self, listener: Weak<ChainListener>);
2639
//TODO: unregister
40+
41+
/// Gets the script and value in satoshis for a given unspent transaction output given a
42+
/// short_channel_id (aka unspent_tx_output_identier). For BTC/tBTC channels the top three
43+
/// bytes are the block height, the next 3 the transaction index within the block, and the
44+
/// final two the output within the transaction.
45+
fn get_chain_utxo(&self, genesis_hash: Sha256dHash, unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError>;
2746
}
2847

2948
/// An interface to send a transaction to the Bitcoin network.
@@ -69,6 +88,7 @@ pub trait FeeEstimator: Sync + Send {
6988
/// Utility to capture some common parts of ChainWatchInterface implementors.
7089
/// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
7190
pub struct ChainWatchInterfaceUtil {
91+
network: Network,
7292
watched: Mutex<(Vec<Script>, Vec<(Sha256dHash, u32)>, bool)>, //TODO: Something clever to optimize this
7393
listeners: Mutex<Vec<Weak<ChainListener>>>,
7494
reentered: AtomicUsize,
@@ -99,11 +119,19 @@ impl ChainWatchInterface for ChainWatchInterfaceUtil {
99119
let mut vec = self.listeners.lock().unwrap();
100120
vec.push(listener);
101121
}
122+
123+
fn get_chain_utxo(&self, genesis_hash: Sha256dHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> {
124+
if genesis_hash != genesis_block(self.network).header.bitcoin_hash() {
125+
return Err(ChainError::NotWatched);
126+
}
127+
Err(ChainError::NotSupported)
128+
}
102129
}
103130

104131
impl ChainWatchInterfaceUtil {
105-
pub fn new(logger: Arc<Logger>) -> ChainWatchInterfaceUtil {
132+
pub fn new(network: Network, logger: Arc<Logger>) -> ChainWatchInterfaceUtil {
106133
ChainWatchInterfaceUtil {
134+
network: network,
107135
watched: Mutex::new((Vec::new(), Vec::new(), false)),
108136
listeners: Mutex::new(Vec::new()),
109137
reentered: AtomicUsize::new(1),

src/chain/transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub struct OutPoint {
1313
}
1414

1515
impl OutPoint {
16-
/// Creates a new `OutPoint` from the txid an the index.
16+
/// Creates a new `OutPoint` from the txid and the index.
1717
pub fn new(txid: Sha256dHash, index: u16) -> OutPoint {
1818
OutPoint { txid, index }
1919
}

src/ln/channel.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,12 @@ impl Channel {
20022002
self.channel_value_satoshis
20032003
}
20042004

2005+
//TODO: Testing purpose only, should be changed in another way after #81
2006+
#[cfg(test)]
2007+
pub fn get_local_keys(&self) -> &ChannelKeys {
2008+
&self.local_keys
2009+
}
2010+
20052011
/// Allowed in any state (including after shutdown)
20062012
pub fn get_channel_update_count(&self) -> u32 {
20072013
self.channel_update_count

src/ln/channelmanager.rs

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,13 +2090,14 @@ mod tests {
20902090
use bitcoin::util::hash::Sha256dHash;
20912091
use bitcoin::blockdata::block::{Block, BlockHeader};
20922092
use bitcoin::blockdata::transaction::{Transaction, TxOut};
2093+
use bitcoin::blockdata::constants::genesis_block;
20932094
use bitcoin::network::constants::Network;
20942095
use bitcoin::network::serialize::serialize;
20952096
use bitcoin::network::serialize::BitcoinHash;
20962097

20972098
use hex;
20982099

2099-
use secp256k1::Secp256k1;
2100+
use secp256k1::{Secp256k1, Message};
21002101
use secp256k1::key::{PublicKey,SecretKey};
21012102

21022103
use crypto::sha2::Sha256;
@@ -2813,7 +2814,7 @@ mod tests {
28132814

28142815
for _ in 0..node_count {
28152816
let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
2816-
let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Arc::clone(&logger)));
2817+
let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
28172818
let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
28182819
let chan_monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone()));
28192820
let node_id = {
@@ -2822,7 +2823,7 @@ mod tests {
28222823
SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
28232824
};
28242825
let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger)).unwrap();
2825-
let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), Arc::clone(&logger));
2826+
let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), chain_monitor.clone(), Arc::clone(&logger));
28262827
nodes.push(Node { chain_monitor, tx_broadcaster, chan_monitor, node, router });
28272828
}
28282829

@@ -3232,4 +3233,78 @@ mod tests {
32323233
assert_eq!(channel_state.by_id.len(), 0);
32333234
assert_eq!(channel_state.short_to_id.len(), 0);
32343235
}
3236+
3237+
#[test]
3238+
fn test_invalid_channel_announcement() {
3239+
//Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs
3240+
let secp_ctx = Secp256k1::new();
3241+
let nodes = create_network(2);
3242+
3243+
let chan_announcement = create_chan_between_nodes(&nodes[0], &nodes[1]);
3244+
3245+
let a_channel_lock = nodes[0].node.channel_state.lock().unwrap();
3246+
let b_channel_lock = nodes[1].node.channel_state.lock().unwrap();
3247+
let as_chan = a_channel_lock.by_id.get(&chan_announcement.3).unwrap();
3248+
let bs_chan = b_channel_lock.by_id.get(&chan_announcement.3).unwrap();
3249+
3250+
let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap() } );
3251+
3252+
let as_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &as_chan.get_local_keys().funding_key);
3253+
let bs_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &bs_chan.get_local_keys().funding_key);
3254+
3255+
let as_network_key = nodes[0].node.get_our_node_id();
3256+
let bs_network_key = nodes[1].node.get_our_node_id();
3257+
3258+
let were_node_one = as_bitcoin_key.serialize()[..] < bs_bitcoin_key.serialize()[..];
3259+
3260+
let mut chan_announcement;
3261+
3262+
macro_rules! dummy_unsigned_msg {
3263+
() => {
3264+
msgs::UnsignedChannelAnnouncement {
3265+
features: msgs::GlobalFeatures::new(),
3266+
chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(),
3267+
short_channel_id: as_chan.get_short_channel_id().unwrap(),
3268+
node_id_1: if were_node_one { as_network_key } else { bs_network_key },
3269+
node_id_2: if !were_node_one { bs_network_key } else { as_network_key },
3270+
bitcoin_key_1: if were_node_one { as_bitcoin_key } else { bs_bitcoin_key },
3271+
bitcoin_key_2: if !were_node_one { bs_bitcoin_key } else { as_bitcoin_key },
3272+
excess_data: Vec::new(),
3273+
};
3274+
}
3275+
}
3276+
3277+
macro_rules! sign_msg {
3278+
($unsigned_msg: expr) => {
3279+
let msghash = Message::from_slice(&Sha256dHash::from_data(&$unsigned_msg.encode()[..])[..]).unwrap();
3280+
let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().funding_key);
3281+
let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().funding_key);
3282+
let as_node_sig = secp_ctx.sign(&msghash, &nodes[0].node.our_network_key);
3283+
let bs_node_sig = secp_ctx.sign(&msghash, &nodes[1].node.our_network_key);
3284+
chan_announcement = msgs::ChannelAnnouncement {
3285+
node_signature_1 : if were_node_one { as_node_sig } else { bs_node_sig},
3286+
node_signature_2 : if !were_node_one { bs_node_sig } else { as_node_sig},
3287+
bitcoin_signature_1: if were_node_one { as_bitcoin_sig } else { bs_bitcoin_sig },
3288+
bitcoin_signature_2 : if !were_node_one { bs_bitcoin_sig } else { as_bitcoin_sig },
3289+
contents: $unsigned_msg
3290+
}
3291+
}
3292+
}
3293+
3294+
let unsigned_msg = dummy_unsigned_msg!();
3295+
sign_msg!(unsigned_msg);
3296+
assert_eq!(nodes[0].router.handle_channel_announcement(&chan_announcement).unwrap(), true);
3297+
let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap() } );
3298+
3299+
// Configured with Network::Testnet
3300+
let mut unsigned_msg = dummy_unsigned_msg!();
3301+
unsigned_msg.chain_hash = genesis_block(Network::Bitcoin).header.bitcoin_hash();
3302+
sign_msg!(unsigned_msg);
3303+
assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err());
3304+
3305+
let mut unsigned_msg = dummy_unsigned_msg!();
3306+
unsigned_msg.chain_hash = Sha256dHash::from_data(&[1,2,3,4,5,6,7,8,9]);
3307+
sign_msg!(unsigned_msg);
3308+
assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err());
3309+
}
32353310
}

0 commit comments

Comments
 (0)