Skip to content

Commit 6a12ff7

Browse files
author
Antoine Riard
committed
Implement get_chain_utxo and ChainError in
ChainWatchInterface to Router check on channel_announcement Needed for BOLT 7
1 parent fa2d2bd commit 6a12ff7

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

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/ln/router.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use secp256k1;
44

55
use bitcoin::util::hash::Sha256dHash;
66

7-
use chain::chaininterface::ChainWatchInterface;
7+
use chain::chaininterface::{ChainError, ChainWatchInterface};
88
use ln::channelmanager;
99
use ln::msgs::{ErrorAction,HandleError,RoutingMessageHandler,MsgEncodable,NetAddress,GlobalFeatures};
1010
use ln::msgs;
@@ -203,13 +203,25 @@ impl RoutingMessageHandler for Router {
203203
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1);
204204
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2);
205205

206-
//TODO: Call blockchain thing to ask if the short_channel_id is valid
207-
//TODO: Only allow bitcoin chain_hash
208-
209206
if msg.contents.features.requires_unknown_bits() {
210207
panic!("Unknown-required-features ChannelAnnouncements should never deserialize!");
211208
}
212209

210+
match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) {
211+
Ok((script_pubkey, _value)) => {
212+
//TODO: Check if script_pubkey matches bitcoin_key_1 and bitcoin_key_2
213+
},
214+
Err(ChainError::NotSupported) => {
215+
// Tenatively accept, potentially exposing us to DoS attacks
216+
},
217+
Err(ChainError::NotWatched) => {
218+
return Err(HandleError{err: "Channel announced on an unknown chain", action: Some(ErrorAction::IgnoreError)});
219+
},
220+
Err(ChainError::UnknownTx) => {
221+
return Err(HandleError{err: "Channel announced without corresponding UTXO entry", action: Some(ErrorAction::IgnoreError)});
222+
},
223+
}
224+
213225
let mut network = self.network_map.write().unwrap();
214226

215227
match network.channels.entry(NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)) {
@@ -643,6 +655,7 @@ mod tests {
643655
use util::logger::Logger;
644656

645657
use bitcoin::util::hash::Sha256dHash;
658+
use bitcoin::network::constants::Network;
646659

647660
use hex;
648661

0 commit comments

Comments
 (0)