X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fchain%2Fchaininterface.rs;h=ef09cbbaaa0f79eb89942860608a315772ef88f3;hb=ab10b050754e4e51b57cd87da8ff588d36565dd0;hp=ad298ce94db35eb4a29bec7c11fc884e6a8cf8af;hpb=4e05b107a3a42a770efb422b15f6cc4e49de2eac;p=rust-lightning diff --git a/src/chain/chaininterface.rs b/src/chain/chaininterface.rs index ad298ce9..ef09cbba 100644 --- a/src/chain/chaininterface.rs +++ b/src/chain/chaininterface.rs @@ -1,39 +1,77 @@ -use bitcoin::blockdata::block::BlockHeader; +//! Traits and utility impls which allow other parts of rust-lightning to interact with the +//! blockchain. +//! +//! Includes traits for monitoring and receiving notifications of new blocks and block +//! disconnections, transaction broadcasting, and feerate information requests. + +use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::transaction::Transaction; use bitcoin::blockdata::script::Script; -use bitcoin::util::hash::Sha256dHash; +use bitcoin::blockdata::constants::genesis_block; +use bitcoin::util::hash::{BitcoinHash, Sha256dHash}; +use bitcoin::network::constants::Network; + +use util::logger::Logger; + +use std::sync::{Mutex,Weak,MutexGuard,Arc}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::collections::HashSet; -use std::sync::{Weak,Mutex}; +/// 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 /// called from inside the library in response to ChainListener events, P2P events, or timer /// events). pub trait ChainWatchInterface: Sync + Send { - /// Provides a scriptPubKey which much be watched for. - fn install_watch_script(&self, script_pub_key: Script); + /// Provides a txid/random-scriptPubKey-in-the-tx which much be watched for. + fn install_watch_tx(&self, txid: &Sha256dHash, script_pub_key: &Script); /// Provides an outpoint which must be watched for, providing any transactions which spend the /// given outpoint. - fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32)); + fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32), out_script: &Script); /// Indicates that a listener needs to see all transactions. fn watch_all_txn(&self); - /// Sends a transaction out to (hopefully) be mined - fn broadcast_transaction(&self, tx: &Transaction); - + /// Register the given listener to receive events. Only a weak pointer is provided and the + /// registration should be freed once that pointer expires. fn register_listener(&self, listener: Weak); //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. +pub trait BroadcasterInterface: Sync + Send { + /// Sends a transaction out to (hopefully) be mined. + fn broadcast_transaction(&self, tx: &Transaction); } /// A trait indicating a desire to listen for events from the chain pub trait ChainListener: Sync + Send { /// Notifies a listener that a block was connected. - /// Note that if a new script/transaction is watched during a block_connected call, the block - /// *must* be re-scanned with the new script/transaction and block_connected should be called - /// again with the same header and (at least) the new transactions. + /// Note that if a new transaction/outpoint is watched during a block_connected call, the block + /// *must* be re-scanned with the new transaction/outpoints and block_connected should be + /// called again with the same header and (at least) the new transactions. + /// + /// Note that if non-new transaction/outpoints may be registered during a call, a second call + /// *must not* happen. + /// /// This also means those counting confirmations using block_connected callbacks should watch /// for duplicate headers and not count them towards confirmations! fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]); @@ -42,97 +80,240 @@ pub trait ChainListener: Sync + Send { fn block_disconnected(&self, header: &BlockHeader); } +/// An enum that represents the speed at which we want a transaction to confirm used for feerate +/// estimation. pub enum ConfirmationTarget { + /// We are happy with this transaction confirming slowly when feerate drops some. Background, + /// We'd like this transaction to confirm without major delay, but 12-18 blocks is fine. Normal, + /// We'd like this transaction to confirm in the next few blocks. HighPriority, } /// A trait which should be implemented to provide feerate information on a number of time /// horizons. +/// /// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're /// called from inside the library in response to ChainListener events, P2P events, or timer /// events). pub trait FeeEstimator: Sync + Send { - fn get_est_sat_per_vbyte(&self, ConfirmationTarget) -> u64; + /// Gets estimated satoshis of fee required per 1000 Weight-Units. + /// + /// Must be no smaller than 253 (ie 1 satoshi-per-byte rounded up to ensure later round-downs + /// don't put us below 1 satoshi-per-byte). + /// + /// This translates to: + /// * satoshis-per-byte * 250 + /// * ceil(satoshis-per-kbyte / 4) + fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u64; +} + +/// Utility for tracking registered txn/outpoints and checking for matches +pub struct ChainWatchedUtil { + watch_all: bool, + + // We are more conservative in matching during testing to ensure everything matches *exactly*, + // even though during normal runtime we take more optimized match approaches... + #[cfg(test)] + watched_txn: HashSet<(Sha256dHash, Script)>, + #[cfg(not(test))] + watched_txn: HashSet