use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::script::Script;
+use bitcoin::blockdata::constants::genesis_block;
use bitcoin::util::hash::Sha256dHash;
+use bitcoin::network::constants::Network;
+use bitcoin::network::serialize::BitcoinHash;
use util::logger::Logger;
use std::sync::{Mutex,Weak,MutexGuard,Arc};
use std::sync::atomic::{AtomicUsize, Ordering};
+/// Used to give chain error details upstream
+pub enum ChainError {
+ /// Client doesn't support UTXO lookup (but the chain hash matches our genesis block hash)
+ NotSupported,
+ /// Chain isn't the one watched
+ NotWatched,
+ /// Tx doesn't exist or is unconfirmed
+ UnknownTx,
+}
+
/// An interface to request notification of certain scripts as they appear the
/// chain.
/// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
fn register_listener(&self, listener: Weak<ChainListener>);
//TODO: unregister
+
+ /// Gets the script and value in satoshis for a given unspent transaction output given a
+ /// short_channel_id (aka unspent_tx_output_identier). For BTC/tBTC channels the top three
+ /// bytes are the block height, the next 3 the transaction index within the block, and the
+ /// final two the output within the transaction.
+ fn get_chain_utxo(&self, genesis_hash: Sha256dHash, unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError>;
}
/// An interface to send a transaction to the Bitcoin network.
/// Utility to capture some common parts of ChainWatchInterface implementors.
/// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
pub struct ChainWatchInterfaceUtil {
+ network: Network,
watched: Mutex<(Vec<Script>, Vec<(Sha256dHash, u32)>, bool)>, //TODO: Something clever to optimize this
listeners: Mutex<Vec<Weak<ChainListener>>>,
reentered: AtomicUsize,
let mut vec = self.listeners.lock().unwrap();
vec.push(listener);
}
+
+ fn get_chain_utxo(&self, genesis_hash: Sha256dHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> {
+ if genesis_hash != genesis_block(self.network).header.bitcoin_hash() {
+ return Err(ChainError::NotWatched);
+ }
+ Err(ChainError::NotSupported)
+ }
}
impl ChainWatchInterfaceUtil {
- pub fn new(logger: Arc<Logger>) -> ChainWatchInterfaceUtil {
+ pub fn new(network: Network, logger: Arc<Logger>) -> ChainWatchInterfaceUtil {
ChainWatchInterfaceUtil {
+ network: network,
watched: Mutex::new((Vec::new(), Vec::new(), false)),
listeners: Mutex::new(Vec::new()),
reentered: AtomicUsize::new(1),
use bitcoin::util::hash::Sha256dHash;
-use chain::chaininterface::ChainWatchInterface;
+use chain::chaininterface::{ChainError, ChainWatchInterface};
use ln::channelmanager;
use ln::msgs::{ErrorAction,HandleError,RoutingMessageHandler,MsgEncodable,NetAddress,GlobalFeatures};
use ln::msgs;
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1);
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2);
- //TODO: Call blockchain thing to ask if the short_channel_id is valid
- //TODO: Only allow bitcoin chain_hash
-
if msg.contents.features.requires_unknown_bits() {
panic!("Unknown-required-features ChannelAnnouncements should never deserialize!");
}
+ match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) {
+ Ok((script_pubkey, _value)) => {
+ //TODO: Check if script_pubkey matches bitcoin_key_1 and bitcoin_key_2
+ },
+ Err(ChainError::NotSupported) => {
+ // Tenatively accept, potentially exposing us to DoS attacks
+ },
+ Err(ChainError::NotWatched) => {
+ return Err(HandleError{err: "Channel announced on an unknown chain", action: Some(ErrorAction::IgnoreError)});
+ },
+ Err(ChainError::UnknownTx) => {
+ return Err(HandleError{err: "Channel announced without corresponding UTXO entry", action: Some(ErrorAction::IgnoreError)});
+ },
+ }
+
let mut network = self.network_map.write().unwrap();
match network.channels.entry(NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)) {
use util::logger::Logger;
use bitcoin::util::hash::Sha256dHash;
+ use bitcoin::network::constants::Network;
use hex;