use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::transaction::{Transaction, TxOut};
-use bitcoin::blockdata::script::Script;
+use bitcoin::blockdata::script::{Builder, Script};
+use bitcoin::blockdata::opcodes;
use bitcoin::network::constants::Network;
use bitcoin::network::serialize::{deserialize, serialize, BitcoinHash};
-use bitcoin::util::hash::Sha256dHash;
+use bitcoin::util::hash::{Sha256dHash, Hash160};
use crypto::digest::Digest;
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
use lightning::chain::transaction::OutPoint;
+use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
use lightning::ln::channelmonitor;
use lightning::ln::channelmanager::{ChannelManager, PaymentFailReason};
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
}
}
+struct KeyProvider {
+ node_secret: SecretKey,
+}
+impl KeysInterface for KeyProvider {
+ fn get_node_secret(&self) -> SecretKey {
+ self.node_secret.clone()
+ }
+
+ fn get_destination_script(&self) -> Script {
+ let secp_ctx = Secp256k1::signing_only();
+ let channel_monitor_claim_key = SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
+ let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
+ Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
+ }
+
+ fn get_shutdown_pubkey(&self) -> PublicKey {
+ let secp_ctx = Secp256k1::signing_only();
+ PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap())
+ }
+
+ fn get_channel_keys(&self, inbound: bool) -> ChannelKeys {
+ let secp_ctx = Secp256k1::without_caps();
+ if inbound {
+ ChannelKeys {
+ funding_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]).unwrap(),
+ revocation_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0]).unwrap(),
+ payment_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0]).unwrap(),
+ delayed_payment_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]).unwrap(),
+ htlc_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]).unwrap(),
+ commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ }
+ } else {
+ ChannelKeys {
+ funding_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
+ revocation_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
+ payment_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
+ delayed_payment_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
+ htlc_base_key: SecretKey::from_slice(&secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
+ commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ }
+ }
+ }
+}
+
#[inline]
pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
reset_rng_state();
let broadcast = Arc::new(TestBroadcaster{});
let monitor = channelmonitor::SimpleManyChannelMonitor::new(watch.clone(), broadcast.clone());
- 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();
- let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key), watch.clone(), Arc::clone(&logger)));
+ let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone() });
+ let channelmanager = ChannelManager::new(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), keys_manager.clone()).unwrap();
+ let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), watch.clone(), Arc::clone(&logger)));
let peers = RefCell::new([false; 256]);
let mut loss_detector = MoneyLossDetector::new(&peers, channelmanager.clone(), monitor.clone(), PeerManager::new(MessageHandler {
--- /dev/null
+//! keysinterface provides keys into rust-lightning and defines some useful enums which describe
+//! spendable on-chain outputs which the user owns and is responsible for using just as any other
+//! on-chain output which is theirs.
+
+use bitcoin::blockdata::transaction::{OutPoint, TxOut};
+use bitcoin::blockdata::script::{Script, Builder};
+use bitcoin::blockdata::opcodes;
+use bitcoin::network::constants::Network;
+use bitcoin::util::hash::Hash160;
+use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
+
+use secp256k1::key::{SecretKey, PublicKey};
+use secp256k1::Secp256k1;
+use secp256k1;
+
+use crypto::hkdf::{hkdf_extract,hkdf_expand};
+
+use util::sha2::Sha256;
+use util::logger::Logger;
+
+use std::sync::Arc;
+
+/// When on-chain outputs are created by rust-lightning an event is generated which informs the
+/// user thereof. This enum describes the format of the output and provides the OutPoint.
+pub enum SpendableOutputDescriptor {
+ /// Outpoint with an output to a script which was provided via KeysInterface, thus you should
+ /// have stored somewhere how to spend script_pubkey!
+ /// Outputs from a justice tx, claim tx or preimage tx
+ StaticOutput {
+ /// The outpoint spendable by user wallet
+ outpoint: OutPoint,
+ /// The output which is referenced by the given outpoint
+ output: TxOut,
+ },
+ /// Outpoint commits to a P2WSH, should be spend by the following witness :
+ /// <local_delayedsig> 0 <witnessScript>
+ /// With input nSequence set to_self_delay.
+ /// Outputs from a HTLC-Success/Timeout tx
+ DynamicOutput {
+ /// Outpoint spendable by user wallet
+ outpoint: OutPoint,
+ /// local_delayedkey = delayed_payment_basepoint_secret + SHA256(per_commitment_point || delayed_payment_basepoint
+ local_delayedkey: SecretKey,
+ /// witness redeemScript encumbering output
+ witness_script: Script,
+ /// nSequence input must commit to self_delay to satisfy script's OP_CSV
+ to_self_delay: u16,
+ }
+}
+
+/// A trait to describe an object which can get user secrets and key material.
+pub trait KeysInterface: Send + Sync {
+ /// Get node secret key (aka node_id or network_key)
+ fn get_node_secret(&self) -> SecretKey;
+ /// Get destination redeemScript to encumber static protocol exit points.
+ fn get_destination_script(&self) -> Script;
+ /// Get shutdown_pubkey to use as PublicKey at channel closure
+ fn get_shutdown_pubkey(&self) -> PublicKey;
+ /// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you
+ /// restarted with some stale data!
+ fn get_channel_keys(&self, inbound: bool) -> ChannelKeys;
+}
+
+/// Set of lightning keys needed to operate a channel as described in BOLT 3
+#[derive(Clone)]
+pub struct ChannelKeys {
+ /// Private key of anchor tx
+ pub funding_key: SecretKey,
+ /// Local secret key for blinded revocation pubkey
+ pub revocation_base_key: SecretKey,
+ /// Local secret key used in commitment tx htlc outputs
+ pub payment_base_key: SecretKey,
+ /// Local secret key used in HTLC tx
+ pub delayed_payment_base_key: SecretKey,
+ /// Local htlc secret key used in commitment tx htlc outputs
+ pub htlc_base_key: SecretKey,
+ /// Commitment seed
+ pub commitment_seed: [u8; 32],
+}
+
+impl ChannelKeys {
+ /// Generate a set of lightning keys needed to operate a channel by HKDF-expanding a given
+ /// random 32-byte seed
+ pub fn new_from_seed(seed: &[u8; 32]) -> ChannelKeys {
+ let mut prk = [0; 32];
+ hkdf_extract(Sha256::new(), b"rust-lightning key gen salt", seed, &mut prk);
+ let secp_ctx = Secp256k1::without_caps();
+
+ let mut okm = [0; 32];
+ hkdf_expand(Sha256::new(), &prk, b"rust-lightning funding key info", &mut okm);
+ let funding_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
+
+ hkdf_expand(Sha256::new(), &prk, b"rust-lightning revocation base key info", &mut okm);
+ let revocation_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
+
+ hkdf_expand(Sha256::new(), &prk, b"rust-lightning payment base key info", &mut okm);
+ let payment_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
+
+ hkdf_expand(Sha256::new(), &prk, b"rust-lightning delayed payment base key info", &mut okm);
+ let delayed_payment_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
+
+ hkdf_expand(Sha256::new(), &prk, b"rust-lightning htlc base key info", &mut okm);
+ let htlc_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
+
+ hkdf_expand(Sha256::new(), &prk, b"rust-lightning local commitment seed info", &mut okm);
+
+ ChannelKeys {
+ funding_key: funding_key,
+ revocation_base_key: revocation_base_key,
+ payment_base_key: payment_base_key,
+ delayed_payment_base_key: delayed_payment_base_key,
+ htlc_base_key: htlc_base_key,
+ commitment_seed: okm
+ }
+ }
+}
+
+/// Simple KeysInterface implementor that takes a 32-byte seed for use as a BIP 32 extended key
+/// and derives keys from that.
+///
+/// Your node_id is seed/0'
+/// ChannelMonitor closes may use seed/1'
+/// Cooperative closes may use seed/2'
+/// The two close keys may be needed to claim on-chain funds!
+pub struct KeysManager {
+ secp_ctx: Secp256k1<secp256k1::All>,
+ node_secret: SecretKey,
+ destination_script: Script,
+ shutdown_pubkey: PublicKey,
+ channel_master_key: ExtendedPrivKey,
+
+ logger: Arc<Logger>,
+}
+
+impl KeysManager {
+ /// Constructs a KeysManager from a 32-byte seed. If the seed is in some way biased (eg your
+ /// RNG is busted) this may panic.
+ pub fn new(seed: &[u8; 32], network: Network, logger: Arc<Logger>) -> KeysManager {
+ let secp_ctx = Secp256k1::new();
+ match ExtendedPrivKey::new_master(&secp_ctx, network.clone(), seed) {
+ Ok(master_key) => {
+ let node_secret = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(0)).expect("Your RNG is busted").secret_key;
+ let destination_script = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(1)) {
+ Ok(destination_key) => {
+ let pubkey_hash160 = Hash160::from_data(&ExtendedPubKey::from_private(&secp_ctx, &destination_key).public_key.serialize()[..]);
+ Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0)
+ .push_slice(pubkey_hash160.as_bytes())
+ .into_script()
+ },
+ Err(_) => panic!("Your RNG is busted"),
+ };
+ let shutdown_pubkey = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(2)) {
+ Ok(shutdown_key) => ExtendedPubKey::from_private(&secp_ctx, &shutdown_key).public_key,
+ Err(_) => panic!("Your RNG is busted"),
+ };
+ let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3)).expect("Your RNG is busted");
+ KeysManager {
+ secp_ctx,
+ node_secret,
+ destination_script,
+ shutdown_pubkey,
+ channel_master_key,
+
+ logger,
+ }
+ },
+ Err(_) => panic!("Your rng is busted"),
+ }
+ }
+}
+
+impl KeysInterface for KeysManager {
+ fn get_node_secret(&self) -> SecretKey {
+ self.node_secret.clone()
+ }
+
+ fn get_destination_script(&self) -> Script {
+ self.destination_script.clone()
+ }
+
+ fn get_shutdown_pubkey(&self) -> PublicKey {
+ self.shutdown_pubkey.clone()
+ }
+
+ fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys {
+ let channel_pubkey = ExtendedPubKey::from_private(&self.secp_ctx, &self. channel_master_key);
+ let mut seed = [0; 32];
+ for (arr, slice) in seed.iter_mut().zip((&channel_pubkey.public_key.serialize()[0..32]).iter()) {
+ *arr = *slice;
+ }
+ ChannelKeys::new_from_seed(&seed)
+ }
+}
pub mod chaininterface;
pub mod transaction;
+pub mod keysinterface;
use secp256k1;
use crypto::digest::Digest;
-use crypto::hkdf::{hkdf_extract,hkdf_expand};
use ln::msgs;
use ln::msgs::{ErrorAction, HandleError, RAACommitmentOrder};
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::transaction::OutPoint;
+use chain::keysinterface::{ChannelKeys, KeysInterface};
use util::{transaction_utils,rng};
use util::ser::Writeable;
use util::sha2::Sha256;
use std::time::Instant;
use std::sync::{Arc};
-pub struct ChannelKeys {
- pub funding_key: SecretKey,
- pub revocation_base_key: SecretKey,
- pub payment_base_key: SecretKey,
- pub delayed_payment_base_key: SecretKey,
- pub htlc_base_key: SecretKey,
- pub channel_close_key: SecretKey,
- pub channel_monitor_claim_key: SecretKey,
- pub commitment_seed: [u8; 32],
-}
-
#[cfg(test)]
pub struct ChannelValueStat {
pub value_to_self_msat: u64,
pub their_max_htlc_value_in_flight_msat: u64, // outgoing
}
-impl ChannelKeys {
- pub fn new_from_seed(seed: &[u8; 32]) -> Result<ChannelKeys, secp256k1::Error> {
- let mut prk = [0; 32];
- hkdf_extract(Sha256::new(), b"rust-lightning key gen salt", seed, &mut prk);
- let secp_ctx = Secp256k1::without_caps();
-
- let mut okm = [0; 32];
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning funding key info", &mut okm);
- let funding_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning revocation base key info", &mut okm);
- let revocation_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning payment base key info", &mut okm);
- let payment_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning delayed payment base key info", &mut okm);
- let delayed_payment_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning htlc base key info", &mut okm);
- let htlc_base_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning channel close key info", &mut okm);
- let channel_close_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning channel monitor claim key info", &mut okm);
- let channel_monitor_claim_key = SecretKey::from_slice(&secp_ctx, &okm)?;
-
- hkdf_expand(Sha256::new(), &prk, b"rust-lightning local commitment seed info", &mut okm);
-
- Ok(ChannelKeys {
- funding_key: funding_key,
- revocation_base_key: revocation_base_key,
- payment_base_key: payment_base_key,
- delayed_payment_base_key: delayed_payment_base_key,
- htlc_base_key: htlc_base_key,
- channel_close_key: channel_close_key,
- channel_monitor_claim_key: channel_monitor_claim_key,
- commitment_seed: okm
- })
- }
-}
-
enum InboundHTLCRemovalReason {
FailRelay(msgs::OnionErrorPacket),
FailMalformed(([u8; 32], u16)),
channel_value_satoshis: u64,
local_keys: ChannelKeys,
+ shutdown_pubkey: PublicKey,
// Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction
// generation start at 0 and count up...this simplifies some parts of implementation at the
}
// Constructors:
- pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Result<Channel, APIError> {
+ pub fn new_outbound(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Result<Channel, APIError> {
+ let chan_keys = keys_provider.get_channel_keys(false);
+
if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(APIError::APIMisuseError{err: "funding value > 2^24"});
}
let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let secp_ctx = Secp256k1::new();
- let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &chan_keys.channel_monitor_claim_key).serialize());
- let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script();
- let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key,
- &PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key),
- &chan_keys.htlc_base_key,
- BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
+ let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
+ &chan_keys.htlc_base_key, BREAKDOWN_TIMEOUT,
+ keys_provider.get_destination_script());
Ok(Channel {
user_id: user_id,
channel_value_satoshis: channel_value_satoshis,
local_keys: chan_keys,
+ shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat: channel_value_satoshis * 1000 - push_msat,
/// Creates a new channel from a remote sides' request for one.
/// Assumes chain_hash has already been checked and corresponds with what we expect!
- pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, ChannelError> {
+ pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, ChannelError> {
+ let chan_keys = keys_provider.get_channel_keys(true);
+
// Check sanity of message fields:
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(ChannelError::Close("funding value > 2^24"));
}
let secp_ctx = Secp256k1::new();
- let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &chan_keys.channel_monitor_claim_key).serialize());
- let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script();
- let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key,
- &PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key),
- &chan_keys.htlc_base_key,
- BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
+ let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
+ &chan_keys.htlc_base_key, BREAKDOWN_TIMEOUT,
+ keys_provider.get_destination_script());
channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
channel_monitor.set_their_to_self_delay(msg.to_self_delay);
announce_publicly: their_announce,
local_keys: chan_keys,
+ shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat: msg.push_msat,
#[inline]
fn get_closing_scriptpubkey(&self) -> Script {
- let our_channel_close_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.channel_close_key).serialize());
+ let our_channel_close_key_hash = Hash160::from_data(&self.shutdown_pubkey.serialize());
Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script()
}
#[cfg(test)]
mod tests {
- use bitcoin::util::hash::Sha256dHash;
+ use bitcoin::util::hash::{Sha256dHash, Hash160};
use bitcoin::util::bip143;
use bitcoin::network::serialize::serialize;
- use bitcoin::blockdata::script::Script;
+ use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::transaction::Transaction;
+ use bitcoin::blockdata::opcodes;
use hex;
use ln::channelmanager::HTLCSource;
use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
use ln::channel::MAX_FUNDING_SATOSHIS;
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
+ use chain::keysinterface::KeysInterface;
use chain::transaction::OutPoint;
use util::test_utils;
use util::logger::Logger;
"MAX_FUNDING_SATOSHIS is greater than all satoshis on existence");
}
+ struct Keys {
+ chan_keys: ChannelKeys,
+ }
+ impl KeysInterface for Keys {
+ fn get_node_secret(&self) -> SecretKey { panic!(); }
+ fn get_destination_script(&self) -> Script {
+ let secp_ctx = Secp256k1::signing_only();
+ let channel_monitor_claim_key = SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
+ let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
+ Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
+ }
+
+ fn get_shutdown_pubkey(&self) -> PublicKey {
+ let secp_ctx = Secp256k1::signing_only();
+ let channel_close_key = SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
+ PublicKey::from_secret_key(&secp_ctx, &channel_close_key)
+ }
+
+ fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys { self.chan_keys.clone() }
+ }
+
#[test]
fn outbound_commitment_test() {
// Test vectors from BOLT 3 Appendix C:
// These aren't set in the test vectors:
revocation_base_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
- channel_close_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
- channel_monitor_claim_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
commitment_seed: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
};
assert_eq!(PublicKey::from_secret_key(&secp_ctx, &chan_keys.funding_key).serialize()[..],
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
+ let keys_provider: Arc<KeysInterface> = Arc::new(Keys { chan_keys });
let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
- let mut chan = Channel::new_outbound(&feeest, chan_keys, their_node_id, 10000000, 100000, false, 42, Arc::clone(&logger)).unwrap(); // Nothing uses their network key in this test
+ let mut chan = Channel::new_outbound(&feeest, &keys_provider, their_node_id, 10000000, 100000, false, 42, Arc::clone(&logger)).unwrap(); // Nothing uses their network key in this test
chan.their_to_self_delay = 144;
chan.our_dust_limit_satoshis = 546;
use chain::chaininterface::{BroadcasterInterface,ChainListener,ChainWatchInterface,FeeEstimator};
use chain::transaction::OutPoint;
-use ln::channel::{Channel, ChannelError, ChannelKeys};
+use ln::channel::{Channel, ChannelError};
use ln::channelmonitor::{ChannelMonitorUpdateErr, ManyChannelMonitor, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS};
use ln::router::{Route,RouteHop};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler, HandleError, RAACommitmentOrder};
+use chain::keysinterface::KeysInterface;
use util::{byte_utils, events, internal_traits, rng};
use util::sha2::Sha256;
use util::ser::{Readable, Writeable};
pending_events: Mutex<Vec<events::Event>>,
+ keys_manager: Arc<KeysInterface>,
+
logger: Arc<Logger>,
}
/// Non-proportional fees are fixed according to our risk using the provided fee estimator.
///
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
- pub fn new(our_network_key: SecretKey, fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
+ pub fn new(fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>, keys_manager: Arc<KeysInterface>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
let secp_ctx = Secp256k1::new();
let res = Arc::new(ChannelManager {
forward_htlcs: HashMap::new(),
claimable_htlcs: HashMap::new(),
}),
- our_network_key,
+ our_network_key: keys_manager.get_node_secret(),
pending_events: Mutex::new(Vec::new()),
+ keys_manager,
+
logger,
});
let weak_res = Arc::downgrade(&res);
///
/// Raises APIError::APIMisuseError when channel_value_satoshis > 2**24 or push_msat being greater than channel_value_satoshis * 1k
pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64) -> Result<(), APIError> {
- let chan_keys = if cfg!(feature = "fuzztarget") {
- ChannelKeys {
- funding_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- revocation_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- payment_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- delayed_payment_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- htlc_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- channel_close_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- channel_monitor_claim_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
- commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- }
- } else {
- let mut key_seed = [0u8; 32];
- rng::fill_bytes(&mut key_seed);
- match ChannelKeys::new_from_seed(&key_seed) {
- Ok(key) => key,
- Err(_) => panic!("RNG is busted!")
- }
- };
-
- let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, push_msat, self.announce_channels_publicly, user_id, Arc::clone(&self.logger))?;
+ let channel = Channel::new_outbound(&*self.fee_estimator, &self.keys_manager, their_network_key, channel_value_satoshis, push_msat, self.announce_channels_publicly, user_id, Arc::clone(&self.logger))?;
let res = channel.get_open_channel(self.genesis_hash.clone(), &*self.fee_estimator);
let mut channel_state = self.channel_state.lock().unwrap();
match channel_state.by_id.entry(channel.channel_id()) {
return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision!", msg.temporary_channel_id.clone()));
}
- let chan_keys = if cfg!(feature = "fuzztarget") {
- ChannelKeys {
- funding_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]).unwrap(),
- revocation_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0]).unwrap(),
- payment_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0]).unwrap(),
- delayed_payment_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]).unwrap(),
- htlc_base_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]).unwrap(),
- channel_close_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0]).unwrap(),
- channel_monitor_claim_key: SecretKey::from_slice(&self.secp_ctx, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0]).unwrap(),
- commitment_seed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- }
- } else {
- let mut key_seed = [0u8; 32];
- rng::fill_bytes(&mut key_seed);
- match ChannelKeys::new_from_seed(&key_seed) {
- Ok(key) => key,
- Err(_) => panic!("RNG is busted!")
- }
- };
-
- let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, false, self.announce_channels_publicly, Arc::clone(&self.logger))
+ let channel = Channel::new_from_req(&*self.fee_estimator, &self.keys_manager, their_node_id.clone(), msg, 0, false, self.announce_channels_publicly, Arc::clone(&self.logger))
.map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id))?;
let accept_msg = channel.get_accept_channel();
channel_state.by_id.insert(channel.channel_id(), channel);
use chain::chaininterface;
use chain::transaction::OutPoint;
use chain::chaininterface::ChainListener;
+ use chain::keysinterface::KeysInterface;
+ use chain::keysinterface;
use ln::channelmanager::{ChannelManager,OnionKeys,PaymentFailReason};
use ln::channelmonitor::{ChannelMonitorUpdateErr, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS};
use ln::router::{Route, RouteHop, Router};
let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
+ let mut seed = [0; 32];
+ rng.fill_bytes(&mut seed);
+ let keys_manager = Arc::new(keysinterface::KeysManager::new(&seed, Network::Testnet, Arc::clone(&logger)));
let chan_monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone()));
- let node_id = {
- let mut key_slice = [0; 32];
- rng.fill_bytes(&mut key_slice);
- SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
- };
- 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();
- let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), chain_monitor.clone(), Arc::clone(&logger));
+ let node = ChannelManager::new(0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger), keys_manager.clone()).unwrap();
+ let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), chain_monitor.clone(), Arc::clone(&logger));
nodes.push(Node { chain_monitor, tx_broadcaster, chan_monitor, node, router,
network_payment_count: payment_count.clone(),
network_chan_count: chan_count.clone(),
use ln::chan_utils::HTLCOutputInCommitment;
use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface};
use chain::transaction::OutPoint;
+use chain::keysinterface::SpendableOutputDescriptor;
use util::ser::{Readable, Writer};
use util::sha2::Sha256;
-use util::byte_utils;
+use util::{byte_utils, events};
use std::collections::HashMap;
use std::sync::{Arc,Mutex};
-use std::{hash,cmp};
+use std::{hash,cmp, mem};
/// An error enum representing a failure to persist a channel monitor update.
#[derive(Clone)]
#[cfg(not(test))]
monitors: Mutex<HashMap<Key, ChannelMonitor>>,
chain_monitor: Arc<ChainWatchInterface>,
- broadcaster: Arc<BroadcasterInterface>
+ broadcaster: Arc<BroadcasterInterface>,
+ pending_events: Mutex<Vec<events::Event>>,
}
impl<Key : Send + cmp::Eq + hash::Hash> ChainListener for SimpleManyChannelMonitor<Key> {
fn block_connected(&self, _header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[u32]) {
- let monitors = self.monitors.lock().unwrap();
- for monitor in monitors.values() {
- let txn_outputs = monitor.block_connected(txn_matched, height, &*self.broadcaster);
- for (ref txid, ref outputs) in txn_outputs {
- for (idx, output) in outputs.iter().enumerate() {
- self.chain_monitor.install_watch_outpoint((txid.clone(), idx as u32), &output.script_pubkey);
+ let mut new_events: Vec<events::Event> = Vec::with_capacity(0);
+ {
+ let monitors = self.monitors.lock().unwrap();
+ for monitor in monitors.values() {
+ let (txn_outputs, spendable_outputs) = monitor.block_connected(txn_matched, height, &*self.broadcaster);
+ if spendable_outputs.len() > 0 {
+ new_events.push(events::Event::SpendableOutputs {
+ outputs: spendable_outputs,
+ });
+ }
+ for (ref txid, ref outputs) in txn_outputs {
+ for (idx, output) in outputs.iter().enumerate() {
+ self.chain_monitor.install_watch_outpoint((txid.clone(), idx as u32), &output.script_pubkey);
+ }
}
}
}
+ let mut pending_events = self.pending_events.lock().unwrap();
+ pending_events.append(&mut new_events);
}
fn block_disconnected(&self, _: &BlockHeader) { }
let res = Arc::new(SimpleManyChannelMonitor {
monitors: Mutex::new(HashMap::new()),
chain_monitor,
- broadcaster
+ broadcaster,
+ pending_events: Mutex::new(Vec::new()),
});
let weak_res = Arc::downgrade(&res);
res.chain_monitor.register_listener(weak_res);
}
}
+impl<Key : Send + cmp::Eq + hash::Hash> events::EventsProvider for SimpleManyChannelMonitor<Key> {
+ fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
+ let mut pending_events = self.pending_events.lock().unwrap();
+ let mut ret = Vec::new();
+ mem::swap(&mut ret, &mut *pending_events);
+ ret
+ }
+}
+
/// If an HTLC expires within this many blocks, don't try to claim it in a shared transaction,
/// instead claiming it in its own individual transaction.
const CLTV_SHARED_CLAIM_BUFFER: u32 = 12;
PrivMode {
revocation_base_key: SecretKey,
htlc_base_key: SecretKey,
+ delayed_payment_base_key: SecretKey,
+ prev_latest_per_commitment_point: Option<PublicKey>,
+ latest_per_commitment_point: Option<PublicKey>,
},
SigsMode {
revocation_base_key: PublicKey,
commitment_transaction_number_obscure_factor: u64,
key_storage: KeyStorage,
- delayed_payment_base_key: PublicKey,
their_htlc_base_key: Option<PublicKey>,
their_delayed_payment_base_key: Option<PublicKey>,
// first is the idx of the first of the two revocation points
commitment_transaction_number_obscure_factor: self.commitment_transaction_number_obscure_factor.clone(),
key_storage: self.key_storage.clone(),
- delayed_payment_base_key: self.delayed_payment_base_key.clone(),
their_htlc_base_key: self.their_htlc_base_key.clone(),
their_delayed_payment_base_key: self.their_delayed_payment_base_key.clone(),
their_cur_revocation_points: self.their_cur_revocation_points.clone(),
if self.funding_txo != other.funding_txo ||
self.commitment_transaction_number_obscure_factor != other.commitment_transaction_number_obscure_factor ||
self.key_storage != other.key_storage ||
- self.delayed_payment_base_key != other.delayed_payment_base_key ||
self.their_htlc_base_key != other.their_htlc_base_key ||
self.their_delayed_payment_base_key != other.their_delayed_payment_base_key ||
self.their_cur_revocation_points != other.their_cur_revocation_points ||
}
impl ChannelMonitor {
- pub(super) fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor {
+ pub(super) fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &SecretKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor {
ChannelMonitor {
funding_txo: None,
commitment_transaction_number_obscure_factor: 0,
key_storage: KeyStorage::PrivMode {
revocation_base_key: revocation_base_key.clone(),
htlc_base_key: htlc_base_key.clone(),
+ delayed_payment_base_key: delayed_payment_base_key.clone(),
+ prev_latest_per_commitment_point: None,
+ latest_per_commitment_point: None,
},
- delayed_payment_base_key: delayed_payment_base_key.clone(),
their_htlc_base_key: None,
their_delayed_payment_base_key: None,
their_cur_revocation_points: None,
/// is important that any clones of this channel monitor (including remote clones) by kept
/// up-to-date as our local commitment transaction is updated.
/// Panics if set_their_to_self_delay has never been called.
+ /// Also update KeyStorage with latest local per_commitment_point to derive local_delayedkey in
+ /// case of onchain HTLC tx
pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>) {
assert!(self.their_to_self_delay.is_some());
self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
feerate_per_kw,
htlc_outputs,
});
+ self.key_storage = if let KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key, ref delayed_payment_base_key, prev_latest_per_commitment_point: _, ref latest_per_commitment_point } = self.key_storage {
+ KeyStorage::PrivMode {
+ revocation_base_key: *revocation_base_key,
+ htlc_base_key: *htlc_base_key,
+ delayed_payment_base_key: *delayed_payment_base_key,
+ prev_latest_per_commitment_point: *latest_per_commitment_point,
+ latest_per_commitment_point: Some(local_keys.per_commitment_point),
+ }
+ } else { unimplemented!(); };
}
/// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
writer.write_all(&byte_utils::be48_to_array(self.commitment_transaction_number_obscure_factor))?;
match self.key_storage {
- KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => {
+ KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key, ref delayed_payment_base_key, ref prev_latest_per_commitment_point, ref latest_per_commitment_point } => {
writer.write_all(&[0; 1])?;
writer.write_all(&revocation_base_key[..])?;
writer.write_all(&htlc_base_key[..])?;
+ writer.write_all(&delayed_payment_base_key[..])?;
+ if let Some(ref prev_latest_per_commitment_point) = *prev_latest_per_commitment_point {
+ writer.write_all(&[1; 1])?;
+ writer.write_all(&prev_latest_per_commitment_point.serialize())?;
+ } else {
+ writer.write_all(&[0; 1])?;
+ }
+ if let Some(ref latest_per_commitment_point) = *latest_per_commitment_point {
+ writer.write_all(&[1; 1])?;
+ writer.write_all(&latest_per_commitment_point.serialize())?;
+ } else {
+ writer.write_all(&[0; 1])?;
+ }
+
},
KeyStorage::SigsMode { .. } => unimplemented!(),
}
- writer.write_all(&self.delayed_payment_base_key.serialize())?;
writer.write_all(&self.their_htlc_base_key.as_ref().unwrap().serialize())?;
writer.write_all(&self.their_delayed_payment_base_key.as_ref().unwrap().serialize())?;
/// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a
/// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
/// HTLC-Success/HTLC-Timeout transactions.
- fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>)) {
+ fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>), Vec<SpendableOutputDescriptor>) {
// Most secp and related errors trying to create keys means we have no hope of constructing
// a spend transaction...so we return no transactions to broadcast
let mut txn_to_broadcast = Vec::new();
let mut watch_outputs = Vec::new();
+ let mut spendable_outputs = Vec::new();
let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
( $thing : expr ) => {
match $thing {
Ok(a) => a,
- Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs))
+ Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
}
};
}
let secret = self.get_secret(commitment_number).unwrap();
let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret));
let (revocation_pubkey, b_htlc_key) = match self.key_storage {
- KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => {
+ KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key, .. } => {
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
(ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key))),
ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))))
};
let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key.unwrap()));
let a_htlc_key = match self.their_htlc_base_key {
- None => return (txn_to_broadcast, (commitment_txid, watch_outputs)),
+ None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &their_htlc_base_key)),
};
if htlc.transaction_output_index as usize >= tx.output.len() ||
tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
- return (txn_to_broadcast, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
+ return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
}
let input = TxIn {
previous_output: BitcoinOutPoint {
watch_outputs.append(&mut tx.output.clone());
self.remote_commitment_txn_on_chain.lock().unwrap().insert(commitment_txid, commitment_number);
}
- if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs)); } // Nothing to be done...probably a false positive/local tx
+ if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
let outputs = vec!(TxOut {
script_pubkey: self.destination_script.clone(),
sign_input!(sighash_parts, input, htlc_idx, value);
}
+ spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
+ outpoint: BitcoinOutPoint { txid: spend_tx.txid(), vout: 0 },
+ output: spend_tx.output[0].clone(),
+ });
txn_to_broadcast.push(spend_tx);
} else if let Some(per_commitment_data) = per_commitment_option {
// While this isn't useful yet, there is a potential race where if a counterparty
} else { None };
if let Some(revocation_point) = revocation_point_option {
let (revocation_pubkey, b_htlc_key) = match self.key_storage {
- KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => {
+ KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key, .. } => {
(ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key))),
ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))))
},
},
};
let a_htlc_key = match self.their_htlc_base_key {
- None => return (txn_to_broadcast, (commitment_txid, watch_outputs)),
+ None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
};
};
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.to_vec());
+ spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
+ outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 },
+ output: single_htlc_tx.output[0].clone(),
+ });
txn_to_broadcast.push(single_htlc_tx);
}
}
}
- if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs)); } // Nothing to be done...probably a false positive/local tx
+ if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
let outputs = vec!(TxOut {
script_pubkey: self.destination_script.clone(),
sign_input!(sighash_parts, input, value.0, value.1.to_vec());
}
+ spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
+ outpoint: BitcoinOutPoint { txid: spend_tx.txid(), vout: 0 },
+ output: spend_tx.output[0].clone(),
+ });
txn_to_broadcast.push(spend_tx);
}
}
}
- (txn_to_broadcast, (commitment_txid, watch_outputs))
+ (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
}
/// Attempst to claim a remote HTLC-Success/HTLC-Timeout s outputs using the revocation key
- fn check_spend_remote_htlc(&self, tx: &Transaction, commitment_number: u64) -> Option<Transaction> {
+ fn check_spend_remote_htlc(&self, tx: &Transaction, commitment_number: u64) -> (Option<Transaction>, Option<SpendableOutputDescriptor>) {
if tx.input.len() != 1 || tx.output.len() != 1 {
- return None;
+ return (None, None)
}
macro_rules! ignore_error {
( $thing : expr ) => {
match $thing {
Ok(a) => a,
- Err(_) => return None
+ Err(_) => return (None, None)
}
};
}
},
};
let delayed_key = match self.their_delayed_payment_base_key {
- None => return None,
+ None => return (None, None),
Some(their_delayed_payment_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &their_delayed_payment_base_key)),
};
let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.their_to_self_delay.unwrap(), &delayed_key);
spend_tx.input[0].witness.push(vec!(1));
spend_tx.input[0].witness.push(redeemscript.into_bytes());
- Some(spend_tx)
- } else { None }
+ let outpoint = BitcoinOutPoint { txid: spend_tx.txid(), vout: 0 };
+ let output = spend_tx.output[0].clone();
+ (Some(spend_tx), Some(SpendableOutputDescriptor::StaticOutput { outpoint, output }))
+ } else { (None, None) }
}
- fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx) -> Vec<Transaction> {
+ fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option<PublicKey>, delayed_payment_base_key: &Option<SecretKey>) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>) {
let mut res = Vec::with_capacity(local_tx.htlc_outputs.len());
+ let mut spendable_outputs = Vec::with_capacity(local_tx.htlc_outputs.len());
for &(ref htlc, ref their_sig, ref our_sig) in local_tx.htlc_outputs.iter() {
if htlc.offered {
htlc_timeout_tx.input[0].witness.push(Vec::new());
htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
+ if let Some(ref per_commitment_point) = *per_commitment_point {
+ if let Some(ref delayed_payment_base_key) = *delayed_payment_base_key {
+ if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, per_commitment_point, delayed_payment_base_key) {
+ spendable_outputs.push(SpendableOutputDescriptor::DynamicOutput {
+ outpoint: BitcoinOutPoint { txid: htlc_timeout_tx.txid(), vout: 0 },
+ local_delayedkey,
+ witness_script: chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.our_to_self_delay, &local_tx.delayed_payment_key),
+ to_self_delay: self.our_to_self_delay
+ });
+ }
+ }
+ }
res.push(htlc_timeout_tx);
} else {
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
htlc_success_tx.input[0].witness.push(payment_preimage.to_vec());
htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
+ if let Some(ref per_commitment_point) = *per_commitment_point {
+ if let Some(ref delayed_payment_base_key) = *delayed_payment_base_key {
+ if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, per_commitment_point, delayed_payment_base_key) {
+ spendable_outputs.push(SpendableOutputDescriptor::DynamicOutput {
+ outpoint: BitcoinOutPoint { txid: htlc_success_tx.txid(), vout: 0 },
+ local_delayedkey,
+ witness_script: chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.our_to_self_delay, &local_tx.delayed_payment_key),
+ to_self_delay: self.our_to_self_delay
+ });
+ }
+ }
+ }
res.push(htlc_success_tx);
}
}
}
- res
+ (res, spendable_outputs)
}
/// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
/// revoked using data in local_claimable_outpoints.
/// Should not be used if check_spend_revoked_transaction succeeds.
- fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> Vec<Transaction> {
+ fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>) {
let commitment_txid = tx.txid();
if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
if local_tx.txid == commitment_txid {
- return self.broadcast_by_local_state(local_tx);
+ match self.key_storage {
+ KeyStorage::PrivMode { revocation_base_key: _, htlc_base_key: _, ref delayed_payment_base_key, prev_latest_per_commitment_point: _, ref latest_per_commitment_point } => {
+ return self.broadcast_by_local_state(local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key));
+ },
+ KeyStorage::SigsMode { .. } => {
+ return self.broadcast_by_local_state(local_tx, &None, &None);
+ }
+ }
}
}
if let &Some(ref local_tx) = &self.prev_local_signed_commitment_tx {
if local_tx.txid == commitment_txid {
- return self.broadcast_by_local_state(local_tx);
+ match self.key_storage {
+ KeyStorage::PrivMode { revocation_base_key: _, htlc_base_key: _, ref delayed_payment_base_key, ref prev_latest_per_commitment_point, .. } => {
+ return self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key));
+ },
+ KeyStorage::SigsMode { .. } => {
+ return self.broadcast_by_local_state(local_tx, &None, &None);
+ }
+ }
}
}
- Vec::new()
+ (Vec::new(), Vec::new())
}
- fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface)-> Vec<(Sha256dHash, Vec<TxOut>)> {
+ fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface)-> (Vec<(Sha256dHash, Vec<TxOut>)>, Vec<SpendableOutputDescriptor>) {
let mut watch_outputs = Vec::new();
+ let mut spendable_outputs = Vec::new();
for tx in txn_matched {
if tx.input.len() == 1 {
// Assuming our keys were not leaked (in which case we're screwed no matter what),
let prevout = &tx.input[0].previous_output;
let mut txn: Vec<Transaction> = Vec::new();
if self.funding_txo.is_none() || (prevout.txid == self.funding_txo.as_ref().unwrap().0.txid && prevout.vout == self.funding_txo.as_ref().unwrap().0.index as u32) {
- let (remote_txn, new_outputs) = self.check_spend_remote_transaction(tx, height);
+ let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height);
txn = remote_txn;
+ spendable_outputs.append(&mut spendable_output);
if !new_outputs.1.is_empty() {
watch_outputs.push(new_outputs);
}
if txn.is_empty() {
- txn = self.check_spend_local_transaction(tx, height);
+ let (remote_txn, mut outputs) = self.check_spend_local_transaction(tx, height);
+ spendable_outputs.append(&mut outputs);
+ txn = remote_txn;
}
} else {
let remote_commitment_txn_on_chain = self.remote_commitment_txn_on_chain.lock().unwrap();
if let Some(commitment_number) = remote_commitment_txn_on_chain.get(&prevout.txid) {
- if let Some(tx) = self.check_spend_remote_htlc(tx, *commitment_number) {
+ let (tx, spendable_output) = self.check_spend_remote_htlc(tx, *commitment_number);
+ if let Some(tx) = tx {
txn.push(tx);
}
+ if let Some(spendable_output) = spendable_output {
+ spendable_outputs.push(spendable_output);
+ }
}
}
for tx in txn.iter() {
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
if self.would_broadcast_at_height(height) {
broadcaster.broadcast_transaction(&cur_local_tx.tx);
- for tx in self.broadcast_by_local_state(&cur_local_tx) {
- broadcaster.broadcast_transaction(&tx);
+ match self.key_storage {
+ KeyStorage::PrivMode { revocation_base_key: _, htlc_base_key: _, ref delayed_payment_base_key, prev_latest_per_commitment_point: _, ref latest_per_commitment_point } => {
+ let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key));
+ spendable_outputs.append(&mut outputs);
+ for tx in txs {
+ broadcaster.broadcast_transaction(&tx);
+ }
+ },
+ KeyStorage::SigsMode { .. } => {
+ let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None);
+ spendable_outputs.append(&mut outputs);
+ for tx in txs {
+ broadcaster.broadcast_transaction(&tx);
+ }
+ }
}
}
}
- watch_outputs
+ (watch_outputs, spendable_outputs)
}
pub(super) fn would_broadcast_at_height(&self, height: u32) -> bool {
let key_storage = match read_bytes!(1)[0] {
0 => {
+ let revocation_base_key = unwrap_obj!(SecretKey::from_slice(&secp_ctx, read_bytes!(32)));
+ let htlc_base_key = unwrap_obj!(SecretKey::from_slice(&secp_ctx, read_bytes!(32)));
+ let delayed_payment_base_key = unwrap_obj!(SecretKey::from_slice(&secp_ctx, read_bytes!(32)));
+ let prev_latest_per_commitment_point = match read_bytes!(1)[0] {
+ 0 => None,
+ 1 => {
+ Some(unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))))
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
+ let latest_per_commitment_point = match read_bytes!(1)[0] {
+ 0 => None,
+ 1 => {
+ Some(unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))))
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
KeyStorage::PrivMode {
- revocation_base_key: unwrap_obj!(SecretKey::from_slice(&secp_ctx, read_bytes!(32))),
- htlc_base_key: unwrap_obj!(SecretKey::from_slice(&secp_ctx, read_bytes!(32))),
+ revocation_base_key,
+ htlc_base_key,
+ delayed_payment_base_key,
+ prev_latest_per_commitment_point,
+ latest_per_commitment_point,
}
},
_ => return Err(DecodeError::InvalidValue),
};
- let delayed_payment_base_key = unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33)));
let their_htlc_base_key = Some(unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))));
let their_delayed_payment_base_key = Some(unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))));
commitment_transaction_number_obscure_factor,
key_storage,
- delayed_payment_base_key,
their_htlc_base_key,
their_delayed_payment_base_key,
their_cur_revocation_points,
};
}
- let delayed_payment_base_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
-
{
// insert_secret correct sequence
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #1 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #2 incorrect (#1 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #3 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #4 incorrect (1,2,3 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #5 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #6 incorrect (5 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #7 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
{
// insert_secret #8 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
// Prune with one old state and a local commitment tx holding a few overlaps with the
// old state.
- let delayed_payment_base_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
- let mut monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ let mut monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), 0, Script::new());
monitor.set_their_to_self_delay(10);
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..10]));
Event::PaymentSent {..} => { /* Hand upstream */ },
Event::PaymentFailed {..} => { /* Hand upstream */ },
Event::PendingHTLCsForwardable {..} => { /* Hand upstream */ },
+ Event::SpendableOutputs { .. } => { /* Hand upstream */ },
Event::SendOpenChannel { ref node_id, ref msg } => {
log_trace!(self, "Handling SendOpenChannel event in peer_handler for node {} for channel {}",
use ln::msgs;
use chain::transaction::OutPoint;
+use chain::keysinterface::SpendableOutputDescriptor;
use bitcoin::blockdata::script::Script;
/// The earliest time at which process_pending_htlc_forwards should be called.
time_forwardable: Instant,
},
+ /// Used to indicate that an output was generated on-chain which you should know how to spend.
+ /// Such an output will *not* ever be spent by rust-lightning, so you need to store them
+ /// somewhere and spend them when you create on-chain spends.
+ SpendableOutputs {
+ /// The outputs which you should store as spendable by you.
+ outputs: Vec<SpendableOutputDescriptor>,
+ },
// Events indicating the network loop should send a message to a peer:
// TODO: Move these into a separate struct and make a top-level enum