use lightning::chain::chaininterface;
use lightning::chain::transaction::OutPoint;
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
-use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
+use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
use lightning::ln::channelmonitor;
use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, HTLCUpdate};
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, ChannelManagerReadArgs};
channel_id: atomic::AtomicU8,
}
impl KeysInterface for KeyProvider {
+ type ChanKeySigner = InMemoryChannelKeys;
+
fn get_node_secret(&self) -> SecretKey {
SecretKey::from_slice(&[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, self.node_id]).unwrap()
}
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[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, self.node_id]).unwrap())
}
- fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys {
- ChannelKeys {
+ fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys {
+ InMemoryChannelKeys {
funding_key: SecretKey::from_slice(&[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, self.node_id]).unwrap(),
revocation_base_key: SecretKey::from_slice(&[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, self.node_id]).unwrap(),
payment_base_key: SecretKey::from_slice(&[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, self.node_id]).unwrap(),
channel_monitors: &monitor_refs,
};
- let res = (<(Sha256d, ChannelManager)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor);
+ let res = (<(Sha256d, ChannelManager<InMemoryChannelKeys>)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor);
for (_, was_good) in $old_monitors.latest_updates_good_at_last_ser.lock().unwrap().iter() {
if !was_good {
// If the last time we updated a monitor we didn't successfully update (and we
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
use lightning::chain::transaction::OutPoint;
-use lightning::chain::keysinterface::{ChannelKeys, KeysInterface};
+use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
use lightning::ln::channelmonitor;
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage};
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
}
struct MoneyLossDetector<'a, 'b> {
- manager: Arc<ChannelManager<'b>>,
+ manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>,
monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>,
handler: PeerManager<Peer<'a>>,
blocks_connected: u32,
}
impl<'a, 'b> MoneyLossDetector<'a, 'b> {
- pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
+ pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
MoneyLossDetector {
manager,
monitor,
counter: AtomicU64,
}
impl KeysInterface for KeyProvider {
+ type ChanKeySigner = InMemoryChannelKeys;
+
fn get_node_secret(&self) -> SecretKey {
self.node_secret.clone()
}
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[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 {
+ fn get_channel_keys(&self, inbound: bool) -> InMemoryChannelKeys {
let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8;
if inbound {
- ChannelKeys {
+ InMemoryChannelKeys {
funding_key: SecretKey::from_slice(&[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, ctr]).unwrap(),
revocation_base_key: SecretKey::from_slice(&[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, ctr]).unwrap(),
payment_base_key: SecretKey::from_slice(&[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, ctr]).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, 6, ctr],
}
} else {
- ChannelKeys {
+ InMemoryChannelKeys {
funding_key: SecretKey::from_slice(&[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, ctr]).unwrap(),
revocation_base_key: SecretKey::from_slice(&[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, 8, ctr]).unwrap(),
payment_base_key: SecretKey::from_slice(&[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, 9, ctr]).unwrap(),
/// A trait to describe an object which can get user secrets and key material.
pub trait KeysInterface: Send + Sync {
+ /// A type which implements ChannelKeys which will be returned by get_channel_keys.
+ type ChanKeySigner : ChannelKeys;
+
/// 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_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;
+ fn get_channel_keys(&self, inbound: bool) -> Self::ChanKeySigner;
/// Get a secret and PRNG seed for construting an onion packet
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]);
/// Get a unique temporary channel id. Channels will be referred to by this until the funding
fn get_channel_id(&self) -> [u8; 32];
}
-/// Set of lightning keys needed to operate a channel as described in BOLT 3
+/// Set of lightning keys needed to operate a channel as described in BOLT 3.
+///
+/// If you're implementing a custom signer, you almost certainly want to implement
+/// Readable/Writable to serialize out a unique reference to this set of keys so
+/// that you can serialize the full ChannelManager object.
+///
+/// (TODO: We shouldn't require that, and should have an API to get them at deser time, due mostly
+/// to the possibility of reentrancy issues by calling the user's code during our deserialization
+/// routine).
+pub trait ChannelKeys : Send {
+ /// Gets the private key for the anchor tx
+ fn funding_key<'a>(&'a self) -> &'a SecretKey;
+ /// Gets the local secret key for blinded revocation pubkey
+ fn revocation_base_key<'a>(&'a self) -> &'a SecretKey;
+ /// Gets the local secret key used in commitment tx htlc outputs
+ fn payment_base_key<'a>(&'a self) -> &'a SecretKey;
+ /// Gets the local secret key used in HTLC tx
+ fn delayed_payment_base_key<'a>(&'a self) -> &'a SecretKey;
+ /// Gets the local htlc secret key used in commitment tx htlc outputs
+ fn htlc_base_key<'a>(&'a self) -> &'a SecretKey;
+ /// Gets the commitment seed
+ fn commitment_seed<'a>(&'a self) -> &'a [u8; 32];
+}
+
#[derive(Clone)]
-pub struct ChannelKeys {
+/// A simple implementation of ChannelKeys that just keeps the private keys in memory.
+pub struct InMemoryChannelKeys {
/// Private key of anchor tx
pub funding_key: SecretKey,
/// Local secret key for blinded revocation pubkey
pub commitment_seed: [u8; 32],
}
-impl_writeable!(ChannelKeys, 0, {
+impl ChannelKeys for InMemoryChannelKeys {
+ fn funding_key(&self) -> &SecretKey { &self.funding_key }
+ fn revocation_base_key(&self) -> &SecretKey { &self.revocation_base_key }
+ fn payment_base_key(&self) -> &SecretKey { &self.payment_base_key }
+ fn delayed_payment_base_key(&self) -> &SecretKey { &self.delayed_payment_base_key }
+ fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
+ fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
+}
+
+impl_writeable!(InMemoryChannelKeys, 0, {
funding_key,
revocation_base_key,
payment_base_key,
}
impl KeysInterface for KeysManager {
+ type ChanKeySigner = InMemoryChannelKeys;
+
fn get_node_secret(&self) -> SecretKey {
self.node_secret.clone()
}
self.shutdown_pubkey.clone()
}
- fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys {
+ fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys {
// We only seriously intend to rely on the channel_master_key for true secure
// entropy, everything else just ensures uniqueness. We rely on the unique_start (ie
// starting_time provided in the constructor) to be unique.
let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_base_key);
let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
- ChannelKeys {
+ InMemoryChannelKeys {
funding_key,
revocation_base_key,
payment_base_key,
// Various functions for key derivation and transaction creation for use within channels. Primarily
// used in Channel and ChannelMonitor.
-pub fn build_commitment_secret(commitment_seed: [u8; 32], idx: u64) -> [u8; 32] {
- let mut res: [u8; 32] = commitment_seed;
+pub fn build_commitment_secret(commitment_seed: &[u8; 32], idx: u64) -> [u8; 32] {
+ let mut res: [u8; 32] = commitment_seed.clone();
for i in 0..48 {
let bitpos = 47 - i;
if idx & (1 << bitpos) == (1 << bitpos) {
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
// inbound channel.
-pub(super) struct Channel {
+pub(super) struct Channel<ChanSigner: ChannelKeys> {
config: ChannelConfig,
user_id: u64,
secp_ctx: Secp256k1<secp256k1::All>,
channel_value_satoshis: u64,
- local_keys: ChannelKeys,
+ local_keys: ChanSigner,
shutdown_pubkey: PublicKey,
// Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction
};
}
-impl Channel {
+impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
// Convert constants + channel value to limits:
fn get_our_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 {
channel_value_satoshis * 1000 / 10 //TODO
}
// Constructors:
- pub fn new_outbound(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel, APIError> {
+ pub fn new_outbound(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface<ChanKeySigner = ChanSigner>>, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel<ChanSigner>, APIError> {
let chan_keys = keys_provider.get_channel_keys(false);
if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
- if Channel::get_our_channel_reserve_satoshis(channel_value_satoshis) < Channel::derive_our_dust_limit_satoshis(background_feerate) {
+ if Channel::<ChanSigner>::get_our_channel_reserve_satoshis(channel_value_satoshis) < Channel::<ChanSigner>::derive_our_dust_limit_satoshis(background_feerate) {
return Err(APIError::FeeRateTooHigh{err: format!("Not enough reserve above dust limit can be found at current fee rate({})", background_feerate), feerate: background_feerate});
}
let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
let secp_ctx = Secp256k1::new();
- let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
- &chan_keys.htlc_base_key, &chan_keys.payment_base_key, &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
+ let channel_monitor = ChannelMonitor::new(chan_keys.revocation_base_key(), chan_keys.delayed_payment_base_key(),
+ chan_keys.htlc_base_key(), chan_keys.payment_base_key(), &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
keys_provider.get_destination_script(), logger.clone());
Ok(Channel {
feerate_per_kw: feerate,
their_dust_limit_satoshis: 0,
- our_dust_limit_satoshis: Channel::derive_our_dust_limit_satoshis(background_feerate),
+ our_dust_limit_satoshis: Channel::<ChanSigner>::derive_our_dust_limit_satoshis(background_feerate),
their_max_htlc_value_in_flight_msat: 0,
their_channel_reserve_satoshis: 0,
their_htlc_minimum_msat: 0,
- our_htlc_minimum_msat: Channel::derive_our_htlc_minimum_msat(feerate),
+ our_htlc_minimum_msat: Channel::<ChanSigner>::derive_our_htlc_minimum_msat(feerate),
their_to_self_delay: 0,
our_to_self_delay: config.own_channel_config.our_to_self_delay,
their_max_accepted_htlcs: 0,
/// 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, keys_provider: &Arc<KeysInterface>, their_node_id: PublicKey, their_local_features: LocalFeatures, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel, ChannelError> {
+ pub fn new_from_req(fee_estimator: &FeeEstimator, keys_provider: &Arc<KeysInterface<ChanKeySigner = ChanSigner>>, their_node_id: PublicKey, their_local_features: LocalFeatures, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel<ChanSigner>, ChannelError> {
let chan_keys = keys_provider.get_channel_keys(true);
let mut local_config = (*config).channel_options.clone();
if msg.htlc_minimum_msat >= (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000 {
return Err(ChannelError::Close("Minimum htlc value is full channel value"));
}
- Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
+ Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
if msg.to_self_delay > config.peer_channel_config_limits.their_to_self_delay || msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
return Err(ChannelError::Close("They wanted our payments to be delayed by a needlessly long period"));
let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
- let our_dust_limit_satoshis = Channel::derive_our_dust_limit_satoshis(background_feerate);
- let our_channel_reserve_satoshis = Channel::get_our_channel_reserve_satoshis(msg.funding_satoshis);
+ let our_dust_limit_satoshis = Channel::<ChanSigner>::derive_our_dust_limit_satoshis(background_feerate);
+ let our_channel_reserve_satoshis = Channel::<ChanSigner>::get_our_channel_reserve_satoshis(msg.funding_satoshis);
if our_channel_reserve_satoshis < our_dust_limit_satoshis {
return Err(ChannelError::Close("Suitable channel reserve not found. aborting"));
}
}
let secp_ctx = Secp256k1::new();
- let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
- &chan_keys.htlc_base_key, &chan_keys.payment_base_key, &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
+ let mut channel_monitor = ChannelMonitor::new(chan_keys.revocation_base_key(), chan_keys.delayed_payment_base_key(),
+ chan_keys.htlc_base_key(), chan_keys.payment_base_key(), &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
keys_provider.get_destination_script(), logger.clone());
channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
channel_monitor.set_their_to_self_delay(msg.to_self_delay);
their_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
their_channel_reserve_satoshis: msg.channel_reserve_satoshis,
their_htlc_minimum_msat: msg.htlc_minimum_msat,
- our_htlc_minimum_msat: Channel::derive_our_htlc_minimum_msat(msg.feerate_per_kw as u64),
+ our_htlc_minimum_msat: Channel::<ChanSigner>::derive_our_htlc_minimum_msat(msg.feerate_per_kw as u64),
their_to_self_delay: msg.to_self_delay,
our_to_self_delay: config.own_channel_config.our_to_self_delay,
their_max_accepted_htlcs: msg.max_accepted_htlcs,
// Utilities to derive keys:
fn build_local_commitment_secret(&self, idx: u64) -> SecretKey {
- let res = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, idx);
+ let res = chan_utils::build_commitment_secret(self.local_keys.commitment_seed(), idx);
SecretKey::from_slice(&res).unwrap()
}
fn get_commitment_transaction_number_obscure_factor(&self) -> u64 {
let mut sha = Sha256::engine();
- let our_payment_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.payment_base_key);
+ let our_payment_basepoint = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.payment_base_key());
if self.channel_outbound {
sha.input(&our_payment_basepoint.serialize());
};
debug_assert!(max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= self.their_channel_reserve_satoshis as i64);
max_commitment_tx_output.0 = cmp::max(max_commitment_tx_output.0, value_to_self_msat as u64);
- debug_assert!(max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis) as i64);
+ debug_assert!(max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis) as i64);
max_commitment_tx_output.1 = cmp::max(max_commitment_tx_output.1, value_to_remote_msat as u64);
}
/// TODO Some magic rust shit to compile-time check this?
fn build_local_transaction_keys(&self, commitment_number: u64) -> Result<TxCreationKeys, ChannelError> {
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(commitment_number));
- let delayed_payment_base = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key);
- let htlc_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key);
+ let delayed_payment_base = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.delayed_payment_base_key());
+ let htlc_basepoint = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.htlc_base_key());
Ok(secp_check!(TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, &delayed_payment_base, &htlc_basepoint, &self.their_revocation_basepoint.unwrap(), &self.their_payment_basepoint.unwrap(), &self.their_htlc_basepoint.unwrap()), "Local tx keys generation got bogus keys"))
}
fn build_remote_transaction_keys(&self) -> Result<TxCreationKeys, ChannelError> {
//TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we
//may see payments to it!
- let payment_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.payment_base_key);
- let revocation_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.revocation_base_key);
- let htlc_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key);
+ let payment_basepoint = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.payment_base_key());
+ let revocation_basepoint = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.revocation_base_key());
+ let htlc_basepoint = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.htlc_base_key());
Ok(secp_check!(TxCreationKeys::new(&self.secp_ctx, &self.their_cur_commitment_point.unwrap(), &self.their_delayed_payment_basepoint.unwrap(), &self.their_htlc_basepoint.unwrap(), &revocation_basepoint, &payment_basepoint, &htlc_basepoint), "Remote tx keys generation got bogus keys"))
}
/// Panics if called before accept_channel/new_from_req
pub fn get_funding_redeemscript(&self) -> Script {
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
- let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key).serialize();
+ let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()).serialize();
let their_funding_key = self.their_funding_pubkey.expect("get_funding_redeemscript only allowed after accept_channel").serialize();
if our_funding_key[..] < their_funding_key[..] {
builder.push_slice(&our_funding_key)
let funding_redeemscript = self.get_funding_redeemscript();
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
- let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key);
+ let our_sig = self.secp_ctx.sign(&sighash, self.local_keys.funding_key());
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
- let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key).serialize();
+ let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()).serialize();
let their_funding_key = self.their_funding_pubkey.unwrap().serialize();
if our_funding_key[..] < their_funding_key[..] {
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
- let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
+ let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, self.local_keys.htlc_base_key()), "Derived invalid key, peer is maliciously selecting parameters");
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
let is_local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key) == keys.a_htlc_key;
Ok((htlc_redeemscript, self.secp_ctx.sign(&sighash, &our_htlc_key), is_local_tx))
if msg.channel_reserve_satoshis < self.our_dust_limit_satoshis {
return Err(ChannelError::Close("Peer never wants payout outputs?"));
}
- if msg.dust_limit_satoshis > Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis) {
+ if msg.dust_limit_satoshis > Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis) {
return Err(ChannelError::Close("Dust limit is bigger than our channel reverse"));
}
if msg.htlc_minimum_msat >= (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000 {
let remote_sighash = hash_to_message!(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
- Ok((remote_initial_commitment_tx, local_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key), local_keys))
+ Ok((remote_initial_commitment_tx, local_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, self.local_keys.funding_key()), local_keys))
}
pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> {
return Err(ChannelError::Close("Remote tried to push more than our max accepted HTLCs"));
}
// Check our_max_htlc_value_in_flight_msat
- if htlc_inbound_value_msat + msg.amount_msat > Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis) {
+ if htlc_inbound_value_msat + msg.amount_msat > Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis) {
return Err(ChannelError::Close("Remote HTLC add would put them over our max HTLC value"));
}
// Check our_channel_reserve_satoshis (we're getting paid, so they have to at least meet
removed_outbound_total_msat += htlc.amount_msat;
}
}
- if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 + removed_outbound_total_msat {
+ if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 + removed_outbound_total_msat {
return Err(ChannelError::Close("Remote HTLC add would put them over their reserve value"));
}
if self.next_remote_htlc_id != msg.htlc_id {
}
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1));
- let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 1);
+ let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed(), self.cur_local_commitment_transaction_number + 1);
// Update state now that we've passed all the can-fail calls...
let mut need_our_commitment = false;
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish"));
}
- Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
+ Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
self.pending_update_fee = Some(msg.feerate_per_kw as u64);
self.channel_update_count += 1;
Ok(())
fn get_last_revoke_and_ack(&self) -> msgs::RevokeAndACK {
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number));
- let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 2);
+ let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed(), self.cur_local_commitment_transaction_number + 2);
msgs::RevokeAndACK {
channel_id: self.channel_id,
per_commitment_secret,
if msg.next_remote_commitment_number > 0 {
match msg.data_loss_protect {
OptionalField::Present(ref data_loss) => {
- if chan_utils::build_commitment_secret(self.local_keys.commitment_seed, INITIAL_COMMITMENT_NUMBER - msg.next_remote_commitment_number + 1) != data_loss.your_last_per_commitment_secret {
+ if chan_utils::build_commitment_secret(self.local_keys.commitment_seed(), INITIAL_COMMITMENT_NUMBER - msg.next_remote_commitment_number + 1) != data_loss.your_last_per_commitment_secret {
return Err(ChannelError::Close("Peer sent a garbage channel_reestablish with secret key not matching the commitment height provided"));
}
if msg.next_remote_commitment_number > INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
Some(msgs::ClosingSigned {
channel_id: self.channel_id,
fee_satoshis: total_fee_satoshis,
- signature: self.secp_ctx.sign(&sighash, &self.local_keys.funding_key),
+ signature: self.secp_ctx.sign(&sighash, &self.local_keys.funding_key()),
})
}
let closing_tx_max_weight = Self::get_closing_transaction_weight(&self.get_closing_scriptpubkey(), self.their_shutdown_scriptpubkey.as_ref().unwrap());
let (closing_tx, used_total_fee) = self.build_closing_transaction($new_feerate * closing_tx_max_weight / 1000, false);
sighash = hash_to_message!(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
- let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key);
+ let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key());
self.last_sent_closing_fee = Some(($new_feerate, used_total_fee));
return Ok((Some(msgs::ClosingSigned {
channel_id: self.channel_id,
}
#[cfg(test)]
- pub fn get_local_keys(&self) -> &ChannelKeys {
+ pub fn get_local_keys(&self) -> &ChanSigner {
&self.local_keys
}
funding_satoshis: self.channel_value_satoshis,
push_msat: self.channel_value_satoshis * 1000 - self.value_to_self_msat,
dust_limit_satoshis: self.our_dust_limit_satoshis,
- max_htlc_value_in_flight_msat: Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
- channel_reserve_satoshis: Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis),
+ max_htlc_value_in_flight_msat: Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
+ channel_reserve_satoshis: Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis),
htlc_minimum_msat: self.our_htlc_minimum_msat,
feerate_per_kw: fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u32,
to_self_delay: self.our_to_self_delay,
max_accepted_htlcs: OUR_MAX_HTLCS,
- funding_pubkey: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key),
- revocation_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.revocation_base_key),
- payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.payment_base_key),
- delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key),
- htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key),
+ funding_pubkey: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()),
+ revocation_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.revocation_base_key()),
+ payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.payment_base_key()),
+ delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.delayed_payment_base_key()),
+ htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.htlc_base_key()),
first_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &local_commitment_secret),
channel_flags: if self.config.announced_channel {1} else {0},
shutdown_scriptpubkey: OptionalField::Present(if self.config.commit_upfront_shutdown_pubkey { self.get_closing_scriptpubkey() } else { Builder::new().into_script() })
msgs::AcceptChannel {
temporary_channel_id: self.channel_id,
dust_limit_satoshis: self.our_dust_limit_satoshis,
- max_htlc_value_in_flight_msat: Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
- channel_reserve_satoshis: Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis),
+ max_htlc_value_in_flight_msat: Channel::<ChanSigner>::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
+ channel_reserve_satoshis: Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis),
htlc_minimum_msat: self.our_htlc_minimum_msat,
minimum_depth: self.minimum_depth,
to_self_delay: self.our_to_self_delay,
max_accepted_htlcs: OUR_MAX_HTLCS,
- funding_pubkey: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key),
- revocation_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.revocation_base_key),
- payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.payment_base_key),
- delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key),
- htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key),
+ funding_pubkey: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()),
+ revocation_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.revocation_base_key()),
+ payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.payment_base_key()),
+ delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.delayed_payment_base_key()),
+ htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.htlc_base_key()),
first_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &local_commitment_secret),
shutdown_scriptpubkey: OptionalField::Present(if self.config.commit_upfront_shutdown_pubkey { self.get_closing_scriptpubkey() } else { Builder::new().into_script() })
}
let remote_sighash = hash_to_message!(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
- Ok((self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key), remote_initial_commitment_tx))
+ Ok((self.secp_ctx.sign(&remote_sighash, self.local_keys.funding_key()), remote_initial_commitment_tx))
}
/// Updates channel state with knowledge of the funding transaction's txid/index, and generates
}
let were_node_one = our_node_id.serialize()[..] < self.their_node_id.serialize()[..];
- let our_bitcoin_key = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key);
+ let our_bitcoin_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key());
let msg = msgs::UnsignedChannelAnnouncement {
features: msgs::GlobalFeatures::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
- let sig = self.secp_ctx.sign(&msghash, &self.local_keys.funding_key);
+ let sig = self.secp_ctx.sign(&msghash, self.local_keys.funding_key());
Ok((msg, sig))
}
let remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true, feerate_per_kw);
let remote_commitment_txid = remote_commitment_tx.0.txid();
let remote_sighash = hash_to_message!(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]);
- let our_sig = self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key);
- log_trace!(self, "Signing remote commitment tx {} with redeemscript {} with pubkey {} -> {}", encode::serialize_hex(&remote_commitment_tx.0), encode::serialize_hex(&funding_script), log_bytes!(PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key).serialize()), log_bytes!(our_sig.serialize_compact()[..]));
+ let our_sig = self.secp_ctx.sign(&remote_sighash, self.local_keys.funding_key());
+ log_trace!(self, "Signing remote commitment tx {} with redeemscript {} with pubkey {} -> {}", encode::serialize_hex(&remote_commitment_tx.0), encode::serialize_hex(&funding_script), log_bytes!(PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()).serialize()), log_bytes!(our_sig.serialize_compact()[..]));
let mut htlc_sigs = Vec::with_capacity(remote_commitment_tx.1);
for &(ref htlc, _) in remote_commitment_tx.2.iter() {
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
- let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
+ let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, self.local_keys.htlc_base_key()), "Derived invalid key, peer is maliciously selecting parameters");
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
log_trace!(self, "Signing remote HTLC tx {} with redeemscript {} with pubkey {} -> {}", encode::serialize_hex(&htlc_tx), encode::serialize_hex(&htlc_redeemscript), log_bytes!(PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key).serialize()), log_bytes!(htlc_sigs.last().unwrap().serialize_compact()[..]));
}
}
}
-impl Writeable for Channel {
+impl<ChanSigner: ChannelKeys + Writeable> Writeable for Channel<ChanSigner> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called but include holding cell updates (and obviously we don't modify self).
}
}
-impl<R : ::std::io::Read> ReadableArgs<R, Arc<Logger>> for Channel {
+impl<R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R, Arc<Logger>> for Channel<ChanSigner> {
fn read(reader: &mut R, logger: Arc<Logger>) -> Result<Self, DecodeError> {
let _ver: u8 = Readable::read(reader)?;
let min_ver: u8 = Readable::read(reader)?;
use ln::channel::MAX_FUNDING_SATOSHIS;
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
- use chain::keysinterface::KeysInterface;
+ use chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
use chain::transaction::OutPoint;
use util::config::UserConfig;
use util::test_utils;
}
struct Keys {
- chan_keys: ChannelKeys,
+ chan_keys: InMemoryChannelKeys,
}
impl KeysInterface for Keys {
+ type ChanKeySigner = InMemoryChannelKeys;
+
fn get_node_secret(&self) -> SecretKey { panic!(); }
fn get_destination_script(&self) -> Script {
let secp_ctx = Secp256k1::signing_only();
PublicKey::from_secret_key(&secp_ctx, &channel_close_key)
}
- fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys { self.chan_keys.clone() }
+ fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys { self.chan_keys.clone() }
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) { panic!(); }
fn get_channel_id(&self) -> [u8; 32] { [0; 32] }
}
let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
let secp_ctx = Secp256k1::new();
- let chan_keys = ChannelKeys {
+ let chan_keys = InMemoryChannelKeys {
funding_key: SecretKey::from_slice(&hex::decode("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(),
payment_base_key: SecretKey::from_slice(&hex::decode("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(),
delayed_payment_base_key: SecretKey::from_slice(&hex::decode("3333333333333333333333333333333333333333333333333333333333333333").unwrap()[..]).unwrap(),
revocation_base_key: SecretKey::from_slice(&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()[..],
+ 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 keys_provider: Arc<KeysInterface<ChanKeySigner = InMemoryChannelKeys>> = Arc::new(Keys { chan_keys });
let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let mut config = UserConfig::default();
config.channel_options.announced_channel = false;
- let mut chan = Channel::new_outbound(&feeest, &keys_provider, their_node_id, 10000000, 100000, 42, Arc::clone(&logger), &config).unwrap(); // Nothing uses their network key in this test
+ let mut chan = Channel::<InMemoryChannelKeys>::new_outbound(&feeest, &keys_provider, their_node_id, 10000000, 100000, 42, Arc::clone(&logger), &config).unwrap(); // Nothing uses their network key in this test
chan.their_to_self_delay = 144;
chan.our_dust_limit_satoshis = 546;
// We can't just use build_local_transaction_keys here as the per_commitment_secret is not
// derived from a commitment_seed, so instead we copy it here and call
// build_commitment_transaction.
- let delayed_payment_base = PublicKey::from_secret_key(&secp_ctx, &chan.local_keys.delayed_payment_base_key);
+ let delayed_payment_base = PublicKey::from_secret_key(&secp_ctx, chan.local_keys.delayed_payment_base_key());
let per_commitment_secret = SecretKey::from_slice(&hex::decode("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
- let htlc_basepoint = PublicKey::from_secret_key(&secp_ctx, &chan.local_keys.htlc_base_key);
+ let htlc_basepoint = PublicKey::from_secret_key(&secp_ctx, chan.local_keys.htlc_base_key());
let keys = TxCreationKeys::new(&secp_ctx, &per_commitment_point, &delayed_payment_base, &htlc_basepoint, &chan.their_revocation_basepoint.unwrap(), &chan.their_payment_basepoint.unwrap(), &chan.their_htlc_basepoint.unwrap()).unwrap();
let mut unsigned_tx: (Transaction, Vec<HTLCOutputInCommitment>);
let mut seed = [0; 32];
seed[0..32].clone_from_slice(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
- assert_eq!(chan_utils::build_commitment_secret(seed, 281474976710655),
+ assert_eq!(chan_utils::build_commitment_secret(&seed, 281474976710655),
hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()[..]);
seed[0..32].clone_from_slice(&hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap());
- assert_eq!(chan_utils::build_commitment_secret(seed, 281474976710655),
+ assert_eq!(chan_utils::build_commitment_secret(&seed, 281474976710655),
hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()[..]);
- assert_eq!(chan_utils::build_commitment_secret(seed, 0xaaaaaaaaaaa),
+ assert_eq!(chan_utils::build_commitment_secret(&seed, 0xaaaaaaaaaaa),
hex::decode("56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528").unwrap()[..]);
- assert_eq!(chan_utils::build_commitment_secret(seed, 0x555555555555),
+ assert_eq!(chan_utils::build_commitment_secret(&seed, 0x555555555555),
hex::decode("9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31").unwrap()[..]);
seed[0..32].clone_from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
- assert_eq!(chan_utils::build_commitment_secret(seed, 1),
+ assert_eq!(chan_utils::build_commitment_secret(&seed, 1),
hex::decode("915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c").unwrap()[..]);
}
use ln::msgs::LocalFeatures;
use ln::onion_utils;
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
-use chain::keysinterface::KeysInterface;
+use chain::keysinterface::{ChannelKeys, KeysInterface};
use util::config::UserConfig;
use util::{byte_utils, events};
use util::ser::{Readable, ReadableArgs, Writeable, Writer};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
+const SIXTY_FIVE_ZEROS: [u8; 65] = [0; 65];
+
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
//
// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
}
// Note this is only exposed in cfg(test):
-pub(super) struct ChannelHolder {
- pub(super) by_id: HashMap<[u8; 32], Channel>,
+pub(super) struct ChannelHolder<ChanSigner: ChannelKeys> {
+ pub(super) by_id: HashMap<[u8; 32], Channel<ChanSigner>>,
pub(super) short_to_id: HashMap<u64, [u8; 32]>,
/// short channel id -> forward infos. Key of 0 means payments received
/// Note that while this is held in the same mutex as the channels themselves, no consistency
/// for broadcast messages, where ordering isn't as strict).
pub(super) pending_msg_events: Vec<events::MessageSendEvent>,
}
-pub(super) struct MutChannelHolder<'a> {
- pub(super) by_id: &'a mut HashMap<[u8; 32], Channel>,
+pub(super) struct MutChannelHolder<'a, ChanSigner: ChannelKeys + 'a> {
+ pub(super) by_id: &'a mut HashMap<[u8; 32], Channel<ChanSigner>>,
pub(super) short_to_id: &'a mut HashMap<u64, [u8; 32]>,
pub(super) forward_htlcs: &'a mut HashMap<u64, Vec<HTLCForwardInfo>>,
pub(super) claimable_htlcs: &'a mut HashMap<PaymentHash, Vec<(u64, HTLCPreviousHopData)>>,
pub(super) pending_msg_events: &'a mut Vec<events::MessageSendEvent>,
}
-impl ChannelHolder {
- pub(super) fn borrow_parts(&mut self) -> MutChannelHolder {
+impl<ChanSigner: ChannelKeys> ChannelHolder<ChanSigner> {
+ pub(super) fn borrow_parts(&mut self) -> MutChannelHolder<ChanSigner> {
MutChannelHolder {
by_id: &mut self.by_id,
short_to_id: &mut self.short_to_id,
/// spam due to quick disconnection/reconnection, updates are not sent until the channel has been
/// offline for a full minute. In order to track this, you must call
/// timer_chan_freshness_every_min roughly once per minute, though it doesn't have to be perfec.
-pub struct ChannelManager<'a> {
+pub struct ChannelManager<'a, ChanSigner: ChannelKeys> {
default_configuration: UserConfig,
genesis_hash: Sha256dHash,
fee_estimator: Arc<FeeEstimator>,
secp_ctx: Secp256k1<secp256k1::All>,
#[cfg(test)]
- pub(super) channel_state: Mutex<ChannelHolder>,
+ pub(super) channel_state: Mutex<ChannelHolder<ChanSigner>>,
#[cfg(not(test))]
- channel_state: Mutex<ChannelHolder>,
+ channel_state: Mutex<ChannelHolder<ChanSigner>>,
our_network_key: SecretKey,
pending_events: Mutex<Vec<events::Event>>,
/// Taken first everywhere where we are making changes before any other locks.
total_consistency_lock: RwLock<()>,
- keys_manager: Arc<KeysInterface>,
+ keys_manager: Arc<KeysInterface<ChanKeySigner = ChanSigner>>,
logger: Arc<Logger>,
}
}
}
-impl<'a> ChannelManager<'a> {
+impl<'a, ChanSigner: ChannelKeys> ChannelManager<'a, ChanSigner> {
/// Constructs a new ChannelManager to hold several channels and route between them.
///
/// This is the main "logic hub" for all channel-related actions, and implements
/// the ChannelManager as a listener to the BlockNotifier and call the BlockNotifier's
/// `block_(dis)connected` methods, which will notify all registered listeners in one
/// go.
- pub fn new(network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor + 'a>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>,keys_manager: Arc<KeysInterface>, config: UserConfig, current_blockchain_height: usize) -> Result<Arc<ChannelManager<'a>>, secp256k1::Error> {
+ pub fn new(network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor + 'a>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>,keys_manager: Arc<KeysInterface<ChanKeySigner = ChanSigner>>, config: UserConfig, current_blockchain_height: usize) -> Result<Arc<ChannelManager<'a, ChanSigner>>, secp256k1::Error> {
let secp_ctx = Secp256k1::new();
let res = Arc::new(ChannelManager {
}
}
- const ZERO:[u8; 65] = [0; 65];
- fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> (PendingHTLCStatus, MutexGuard<ChannelHolder>) {
+ fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> (PendingHTLCStatus, MutexGuard<ChannelHolder<ChanSigner>>) {
macro_rules! return_malformed_err {
($msg: expr, $err_code: expr) => {
{
} else {
let mut new_packet_data = [0; 20*65];
chacha.process(&msg.onion_routing_packet.hop_data[65..], &mut new_packet_data[0..19*65]);
- chacha.process(&ChannelManager::ZERO[..], &mut new_packet_data[19*65..]);
+ chacha.process(&SIXTY_FIVE_ZEROS[..], &mut new_packet_data[19*65..]);
let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap();
/// only fails if the channel does not yet have an assigned short_id
/// May be called with channel_state already locked!
- fn get_channel_update(&self, chan: &Channel) -> Result<msgs::ChannelUpdate, LightningError> {
+ fn get_channel_update(&self, chan: &Channel<ChanSigner>) -> Result<msgs::ChannelUpdate, LightningError> {
let short_channel_id = match chan.get_short_channel_id() {
None => return Err(LightningError{err: "Channel not yet established", action: msgs::ErrorAction::IgnoreError}),
Some(id) => id,
}
}
- fn get_announcement_sigs(&self, chan: &Channel) -> Option<msgs::AnnouncementSignatures> {
+ fn get_announcement_sigs(&self, chan: &Channel<ChanSigner>) -> Option<msgs::AnnouncementSignatures> {
if !chan.should_announce() { return None }
let (announcement, our_bitcoin_sig) = match chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) {
/// to fail and take the channel_state lock for each iteration (as we take ownership and may
/// drop it). In other words, no assumptions are made that entries in claimable_htlcs point to
/// still-available channels.
- fn fail_htlc_backwards_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder>, source: HTLCSource, payment_hash: &PaymentHash, onion_error: HTLCFailReason) {
+ fn fail_htlc_backwards_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<ChanSigner>>, source: HTLCSource, payment_hash: &PaymentHash, onion_error: HTLCFailReason) {
//TODO: There is a timing attack here where if a node fails an HTLC back to us they can
//identify whether we sent it or not based on the (I presume) very different runtime
//between the branches here. We should make this async and move it into the forward HTLCs
true
} else { false }
}
- fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder>, source: HTLCSource, payment_preimage: PaymentPreimage) {
+ fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<ChanSigner>>, source: HTLCSource, payment_preimage: PaymentPreimage) {
let (their_node_id, err) = loop {
match source {
HTLCSource::OutboundRoute { .. } => {
}
}
-impl<'a> events::MessageSendEventsProvider for ChannelManager<'a> {
+impl<'a, ChanSigner: ChannelKeys> events::MessageSendEventsProvider for ChannelManager<'a, ChanSigner> {
fn get_and_clear_pending_msg_events(&self) -> Vec<events::MessageSendEvent> {
// TODO: Event release to users and serialization is currently race-y: it's very easy for a
// user to serialize a ChannelManager with pending events in it and lose those events on
}
}
-impl<'a> events::EventsProvider for ChannelManager<'a> {
+impl<'a, ChanSigner: ChannelKeys> events::EventsProvider for ChannelManager<'a, ChanSigner> {
fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
// TODO: Event release to users and serialization is currently race-y: it's very easy for a
// user to serialize a ChannelManager with pending events in it and lose those events on
}
}
-impl<'a> ChainListener for ChannelManager<'a> {
+impl<'a, ChanSigner: ChannelKeys> ChainListener for ChannelManager<'a, ChanSigner> {
fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) {
let header_hash = header.bitcoin_hash();
log_trace!(self, "Block {} at height {} connected with {} txn matched", header_hash, height, txn_matched.len());
}
}
-impl<'a> ChannelMessageHandler for ChannelManager<'a> {
+impl<'a, ChanSigner: ChannelKeys> ChannelMessageHandler for ChannelManager<'a, ChanSigner> {
//TODO: Handle errors and close channel (or so)
fn handle_open_channel(&self, their_node_id: &PublicKey, their_local_features: LocalFeatures, msg: &msgs::OpenChannel) -> Result<(), LightningError> {
let _ = self.total_consistency_lock.read().unwrap();
}
}
-impl<'a> Writeable for ChannelManager<'a> {
+impl<'a, ChanSigner: ChannelKeys + Writeable> Writeable for ChannelManager<'a, ChanSigner> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
let _ = self.total_consistency_lock.write().unwrap();
/// 5) Move the ChannelMonitors into your local ManyChannelMonitor.
/// 6) Disconnect/connect blocks on the ChannelManager.
/// 7) Register the new ChannelManager with your ChainWatchInterface.
-pub struct ChannelManagerReadArgs<'a, 'b> {
+pub struct ChannelManagerReadArgs<'a, 'b, ChanSigner: ChannelKeys> {
/// The keys provider which will give us relevant keys. Some keys will be loaded during
/// deserialization.
- pub keys_manager: Arc<KeysInterface>,
+ pub keys_manager: Arc<KeysInterface<ChanKeySigner = ChanSigner>>,
/// The fee_estimator for use in the ChannelManager in the future.
///
pub channel_monitors: &'a HashMap<OutPoint, &'a ChannelMonitor>,
}
-impl<'a, 'b, R : ::std::io::Read> ReadableArgs<R, ChannelManagerReadArgs<'a, 'b>> for (Sha256dHash, ChannelManager<'b>) {
- fn read(reader: &mut R, args: ChannelManagerReadArgs<'a, 'b>) -> Result<Self, DecodeError> {
+impl<'a, 'b, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R, ChannelManagerReadArgs<'a, 'b, ChanSigner>> for (Sha256dHash, ChannelManager<'b, ChanSigner>) {
+ fn read(reader: &mut R, args: ChannelManagerReadArgs<'a, 'b, ChanSigner>) -> Result<Self, DecodeError> {
let _ver: u8 = Readable::read(reader)?;
let min_ver: u8 = Readable::read(reader)?;
if min_ver > SERIALIZATION_VERSION {
let mut by_id = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
let mut short_to_id = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
for _ in 0..channel_count {
- let mut channel: Channel = ReadableArgs::read(reader, args.logger.clone())?;
+ let mut channel: Channel<ChanSigner> = ReadableArgs::read(reader, args.logger.clone())?;
if channel.last_block_connected != last_block_hash {
return Err(DecodeError::InvalidValue);
}
use ln::router::{Route, Router};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler, LocalFeatures};
+use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::test_utils;
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
use util::errors::APIError;
pub tx_broadcaster: Arc<test_utils::TestBroadcaster>,
pub chan_monitor: Arc<test_utils::TestChannelMonitor>,
pub keys_manager: Arc<test_utils::TestKeysInterface>,
- pub node: Arc<ChannelManager<'b>>,
+ pub node: Arc<ChannelManager<'b, EnforcingChannelKeys>>,
pub router: Router,
pub node_seed: [u8; 32],
pub network_payment_count: Rc<RefCell<u8>>,
use chain::transaction::OutPoint;
use chain::chaininterface::{ChainListener, ChainWatchInterfaceUtil};
-use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor, KeysManager};
-use chain::keysinterface;
+use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT};
use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY};
use ln::router::{Route, RouteHop};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, LocalFeatures, ErrorAction};
+use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::test_utils;
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
use util::errors::APIError;
// Instantiate channel parameters where we push the maximum msats given our
// funding satoshis
let channel_value_sat = 31337; // same as funding satoshis
- let channel_reserve_satoshis = Channel::get_our_channel_reserve_satoshis(channel_value_sat);
+ let channel_reserve_satoshis = Channel::<EnforcingChannelKeys>::get_our_channel_reserve_satoshis(channel_value_sat);
let push_msat = (channel_value_sat - channel_reserve_satoshis) * 1000;
// Have node0 initiate a channel to node1 with aforementioned parameters
let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap(), is_permanent: false } );
- let as_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &as_chan.get_local_keys().funding_key);
- let bs_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &bs_chan.get_local_keys().funding_key);
+ let as_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &as_chan.get_local_keys().inner.funding_key);
+ let bs_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &bs_chan.get_local_keys().inner.funding_key);
let as_network_key = nodes[0].node.get_our_node_id();
let bs_network_key = nodes[1].node.get_our_node_id();
macro_rules! sign_msg {
($unsigned_msg: expr) => {
let msghash = Message::from_slice(&Sha256dHash::hash(&$unsigned_msg.encode()[..])[..]).unwrap();
- let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().funding_key);
- let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().funding_key);
+ let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().inner.funding_key);
+ let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().inner.funding_key);
let as_node_sig = secp_ctx.sign(&msghash, &nodes[0].keys_manager.get_node_secret());
let bs_node_sig = secp_ctx.sign(&msghash, &nodes[1].keys_manager.get_node_secret());
chan_announcement = msgs::ChannelAnnouncement {
let (_, nodes_0_deserialized) = {
let mut channel_monitors = HashMap::new();
channel_monitors.insert(chan_0_monitor.get_funding_txo().unwrap(), &chan_0_monitor);
- <(Sha256dHash, ChannelManager)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
+ <(Sha256dHash, ChannelManager<EnforcingChannelKeys>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
default_config: config,
keys_manager,
fee_estimator: Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }),
let (_, nodes_0_deserialized) = {
let mut channel_monitors = HashMap::new();
channel_monitors.insert(chan_0_monitor.get_funding_txo().unwrap(), &chan_0_monitor);
- <(Sha256dHash, ChannelManager)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
+ <(Sha256dHash, ChannelManager<EnforcingChannelKeys>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
default_config: UserConfig::default(),
keys_manager,
fee_estimator: Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }),
let mut nodes_0_read = &nodes_0_serialized[..];
let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&nodes[0].node_seed, Network::Testnet, Arc::new(test_utils::TestLogger::new())));
- let (_, nodes_0_deserialized) = <(Sha256dHash, ChannelManager)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
+ let (_, nodes_0_deserialized) = <(Sha256dHash, ChannelManager<EnforcingChannelKeys>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
default_config: UserConfig::default(),
keys_manager,
fee_estimator: Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }),
let nodes = create_network(2, &cfgs);
// We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in Channel::new_outbound()
- let keys_manager: Arc<KeysInterface> = Arc::new(KeysManager::new(&nodes[0].node_seed, Network::Testnet, Arc::new(test_utils::TestLogger::new()), 10, 20));
+ let keys_manager: Arc<KeysInterface<ChanKeySigner = EnforcingChannelKeys>> = Arc::new(test_utils::TestKeysInterface::new(&nodes[0].node_seed, Network::Testnet, Arc::new(test_utils::TestLogger::new())));
if let Err(error) = Channel::new_outbound(&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), 1000000, 1000000, 0, Arc::new(test_utils::TestLogger::new()), &low_our_to_self_config) {
match error {
APIError::APIMisuseError { err } => { assert_eq!(err, "Configured with an unreasonable our_to_self_delay putting user funds at risks"); },
let monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone(), logger.clone(), feeest.clone()));
let mut channel_monitors = HashMap::new();
channel_monitors.insert(OutPoint { txid: chan.3.txid(), index: 0 }, &chan_monitor);
- let node_state_0 = <(Sha256dHash, ChannelManager)>::read(&mut ::std::io::Cursor::new(previous_node_state), ChannelManagerReadArgs {
- keys_manager: Arc::new(keysinterface::KeysManager::new(&nodes[0].node_seed, Network::Testnet, Arc::clone(&logger), 42, 21)),
+ let node_state_0 = <(Sha256dHash, ChannelManager<EnforcingChannelKeys>)>::read(&mut ::std::io::Cursor::new(previous_node_state), ChannelManagerReadArgs {
+ keys_manager: Arc::new(test_utils::TestKeysInterface::new(&nodes[0].node_seed, Network::Testnet, Arc::clone(&logger))),
fee_estimator: feeest.clone(),
monitor: monitor.clone(),
logger: Arc::clone(&logger),
--- /dev/null
+use chain::keysinterface::{ChannelKeys, InMemoryChannelKeys};
+
+use secp256k1::key::SecretKey;
+
+/// Enforces some rules on ChannelKeys calls. Eventually we will probably want to expose a variant
+/// of this which would essentially be what you'd want to run on a hardware wallet.
+pub struct EnforcingChannelKeys {
+ pub inner: InMemoryChannelKeys,
+}
+
+impl EnforcingChannelKeys {
+ pub fn new(inner: InMemoryChannelKeys) -> Self {
+ Self {
+ inner,
+ }
+ }
+}
+impl ChannelKeys for EnforcingChannelKeys {
+ fn funding_key(&self) -> &SecretKey { self.inner.funding_key() }
+ fn revocation_base_key(&self) -> &SecretKey { self.inner.revocation_base_key() }
+ fn payment_base_key(&self) -> &SecretKey { self.inner.payment_base_key() }
+ fn delayed_payment_base_key(&self) -> &SecretKey { self.inner.delayed_payment_base_key() }
+ fn htlc_base_key(&self) -> &SecretKey { self.inner.htlc_base_key() }
+ fn commitment_seed(&self) -> &[u8; 32] { self.inner.commitment_seed() }
+}
+
+impl_writeable!(EnforcingChannelKeys, 0, {
+ inner
+});
#[cfg(test)]
pub(crate) mod test_utils;
+/// impls of traits that add exra enforcement on the way they're called. Useful for detecting state
+/// machine errors and used in fuzz targets and tests.
+#[cfg(any(test, feature = "fuzztarget"))]
+pub mod enforcing_trait_impls;
+
#[macro_use]
pub(crate) mod fuzz_wrappers;
use ln::msgs::LocalFeatures;
use ln::msgs::{LightningError};
use ln::channelmonitor::HTLCUpdate;
+use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::events;
use util::logger::{Logger, Level, Record};
use util::ser::{ReadableArgs, Writer};
}
impl keysinterface::KeysInterface for TestKeysInterface {
+ type ChanKeySigner = EnforcingChannelKeys;
+
fn get_node_secret(&self) -> SecretKey { self.backing.get_node_secret() }
fn get_destination_script(&self) -> Script { self.backing.get_destination_script() }
fn get_shutdown_pubkey(&self) -> PublicKey { self.backing.get_shutdown_pubkey() }
- fn get_channel_keys(&self, inbound: bool) -> keysinterface::ChannelKeys { self.backing.get_channel_keys(inbound) }
+ fn get_channel_keys(&self, inbound: bool) -> EnforcingChannelKeys { EnforcingChannelKeys::new(self.backing.get_channel_keys(inbound)) }
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
match *self.override_session_priv.lock().unwrap() {