Skip to content

Few more simple signer API additions #419

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ use bitcoin_hashes::sha256d::Hash as Sha256d;
use lightning::chain::chaininterface;
use lightning::chain::transaction::OutPoint;
use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil};
use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
use lightning::chain::keysinterface::{KeysInterface, InMemoryChannelKeys};
use lightning::ln::channelmonitor;
use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, HTLCUpdate};
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, ChannelManagerReadArgs};
use lightning::ln::router::{Route, RouteHop};
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, ErrorAction, LightningError, UpdateAddHTLC, LocalFeatures};
use lightning::util::enforcing_trait_impls::EnforcingChannelKeys;
use lightning::util::events;
use lightning::util::logger::Logger;
use lightning::util::config::UserConfig;
Expand Down Expand Up @@ -130,7 +131,7 @@ struct KeyProvider {
channel_id: atomic::AtomicU8,
}
impl KeysInterface for KeyProvider {
type ChanKeySigner = InMemoryChannelKeys;
type ChanKeySigner = EnforcingChannelKeys;

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()
Expand All @@ -148,15 +149,15 @@ impl KeysInterface for KeyProvider {
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) -> InMemoryChannelKeys {
InMemoryChannelKeys {
fn get_channel_keys(&self, _inbound: bool) -> EnforcingChannelKeys {
EnforcingChannelKeys::new(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(),
delayed_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, 7, self.node_id]).unwrap(),
htlc_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, self.node_id]).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, 9, self.node_id],
}
})
}

fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
Expand Down Expand Up @@ -225,7 +226,7 @@ pub fn do_test(data: &[u8]) {
channel_monitors: &monitor_refs,
};

let res = (<(Sha256d, ChannelManager<InMemoryChannelKeys>)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor);
let res = (<(Sha256d, ChannelManager<EnforcingChannelKeys>)>::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
Expand Down
13 changes: 7 additions & 6 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
use lightning::ln::router::Router;
use lightning::util::events::{EventsProvider,Event};
use lightning::util::enforcing_trait_impls::EnforcingChannelKeys;
use lightning::util::logger::Logger;
use lightning::util::config::UserConfig;

Expand Down Expand Up @@ -135,7 +136,7 @@ impl<'a> Hash for Peer<'a> {
}

struct MoneyLossDetector<'a, 'b> {
manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>,
manager: Arc<ChannelManager<'b, EnforcingChannelKeys>>,
monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>,
handler: PeerManager<Peer<'a>>,

Expand All @@ -148,7 +149,7 @@ struct MoneyLossDetector<'a, 'b> {
blocks_connected: u32,
}
impl<'a, 'b> MoneyLossDetector<'a, 'b> {
pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b, InMemoryChannelKeys>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc<ChannelManager<'b, EnforcingChannelKeys>>, monitor: Arc<channelmonitor::SimpleManyChannelMonitor<OutPoint>>, handler: PeerManager<Peer<'a>>) -> Self {
MoneyLossDetector {
manager,
monitor,
Expand Down Expand Up @@ -228,7 +229,7 @@ struct KeyProvider {
counter: AtomicU64,
}
impl KeysInterface for KeyProvider {
type ChanKeySigner = InMemoryChannelKeys;
type ChanKeySigner = EnforcingChannelKeys;

fn get_node_secret(&self) -> SecretKey {
self.node_secret.clone()
Expand All @@ -246,9 +247,9 @@ impl KeysInterface for KeyProvider {
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) -> InMemoryChannelKeys {
fn get_channel_keys(&self, inbound: bool) -> EnforcingChannelKeys {
let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8;
if inbound {
EnforcingChannelKeys::new(if inbound {
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(),
Expand All @@ -266,7 +267,7 @@ impl KeysInterface for KeyProvider {
htlc_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, 11, 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, 12, ctr],
}
}
})
}

fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
Expand Down
39 changes: 35 additions & 4 deletions lightning/src/chain/keysinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use bitcoin::util::bip143;
use bitcoin_hashes::{Hash, HashEngine};
use bitcoin_hashes::sha256::HashEngine as Sha256State;
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use bitcoin_hashes::hash160::Hash as Hash160;

use secp256k1::key::{SecretKey, PublicKey};
Expand All @@ -20,9 +21,11 @@ use secp256k1;

use util::byte_utils;
use util::logger::Logger;
use util::ser::Writeable;

use ln::chan_utils;
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
use ln::msgs;

use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
Expand Down Expand Up @@ -139,7 +142,21 @@ pub trait ChannelKeys : Send {
/// TODO: Document the things someone using this interface should enforce before signing.
/// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
/// making the callee generate it via some util function we expose)!
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, absolute_fee: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;

/// Create a signature for a (proposed) closing transaction.
///
/// Note that, due to rounding, there may be one "missing" satoshi, and either party may have
/// chosen to forgo their output as dust.
fn sign_closing_transaction<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;

/// Signs a channel announcement message with our funding key, proving it comes from one
/// of the channel participants.
///
/// Note that if this fails or is rejected, the channel will not be publicly announced and
/// our counterparty may (though likely will not) close the channel on us for violating the
/// protocol.
fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
}

#[derive(Clone)]
Expand Down Expand Up @@ -167,10 +184,9 @@ impl ChannelKeys for InMemoryChannelKeys {
fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }


fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
if commitment_tx.input.len() != 1 { return Err(()); }
let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_script, channel_value_satoshis)[..]);
let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_redeemscript, channel_value_satoshis)[..]);
let commitment_sig = secp_ctx.sign(&commitment_sighash, &self.funding_key);

let commitment_txid = commitment_tx.txid();
Expand All @@ -191,6 +207,21 @@ impl ChannelKeys for InMemoryChannelKeys {

Ok((commitment_sig, htlc_sigs))
}

fn sign_closing_transaction<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
if closing_tx.input.len() != 1 { return Err(()); }
if closing_tx.input[0].witness.len() != 0 { return Err(()); }
if closing_tx.output.len() > 2 { return Err(()); }

let sighash = hash_to_message!(&bip143::SighashComponents::new(closing_tx)
.sighash_all(&closing_tx.input[0], &channel_funding_redeemscript, channel_value_satoshis)[..]);
Ok(secp_ctx.sign(&sighash, &self.funding_key))
}

fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
Ok(secp_ctx.sign(&msghash, &self.funding_key))
}
}

impl_writeable!(InMemoryChannelKeys, 0, {
Expand Down
64 changes: 47 additions & 17 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
#[cfg(not(test))]
last_local_commitment_txn: Vec<Transaction>,

last_sent_closing_fee: Option<(u64, u64)>, // (feerate, fee)
last_sent_closing_fee: Option<(u64, u64, Signature)>, // (feerate, fee, our_sig)

/// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this
/// to detect unconfirmation after a serialize-unserialize roundtrip where we may not see a full
Expand Down Expand Up @@ -2665,14 +2665,16 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
let proposed_total_fee_satoshis = proposed_feerate * tx_weight / 1000;

let (closing_tx, total_fee_satoshis) = self.build_closing_transaction(proposed_total_fee_satoshis, false);
let funding_redeemscript = self.get_funding_redeemscript();
let 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.local_keys
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like if let Ok(our_sig) { Some() } else { None } would avoid conversion to option and calling unwrap. Would make code easier to review too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ehh, I dont think so? map_err()? is pretty clear.

.sign_closing_transaction(self.channel_value_satoshis, &self.get_funding_redeemscript(), &closing_tx, &self.secp_ctx)
.ok();
if our_sig.is_none() { return None; }

self.last_sent_closing_fee = Some((proposed_feerate, total_fee_satoshis));
self.last_sent_closing_fee = Some((proposed_feerate, total_fee_satoshis, our_sig.clone().unwrap()));
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: our_sig.unwrap(),
})
}

Expand Down Expand Up @@ -2749,6 +2751,28 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
}

fn build_signed_closing_transaction(&self, tx: &mut Transaction, their_sig: &Signature, our_sig: &Signature) {
if tx.input.len() != 1 { panic!("Tried to sign closing transaction that had input count != 1!"); }
if tx.input[0].witness.len() != 0 { panic!("Tried to re-sign closing transaction"); }
if tx.output.len() > 2 { panic!("Tried to sign bogus closing transaction"); }

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 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());
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
} else {
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
}
tx.input[0].witness[1].push(SigHashType::All as u8);
tx.input[0].witness[2].push(SigHashType::All as u8);

tx.input[0].witness.push(self.get_funding_redeemscript().into_bytes());
}

pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option<msgs::ClosingSigned>, Option<Transaction>), ChannelError> {
if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK {
return Err(ChannelError::Close("Remote end sent us a closing_signed before both sides provided a shutdown"));
Expand Down Expand Up @@ -2781,9 +2805,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
},
};

if let Some((_, last_fee)) = self.last_sent_closing_fee {
if let Some((_, last_fee, our_sig)) = self.last_sent_closing_fee {
if last_fee == msg.fee_satoshis {
self.sign_commitment_transaction(&mut closing_tx, &msg.signature);
self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &our_sig);
self.channel_state = ChannelState::ShutdownComplete as u32;
self.channel_update_count += 1;
return Ok((None, Some(closing_tx)));
Expand All @@ -2794,9 +2818,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
($new_feerate: expr) => {
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());
self.last_sent_closing_fee = Some(($new_feerate, used_total_fee));
let our_sig = self.local_keys
.sign_closing_transaction(self.channel_value_satoshis, &funding_redeemscript, &closing_tx, &self.secp_ctx)
.map_err(|_| ChannelError::Close("External signer refused to sign closing transaction"))?;
self.last_sent_closing_fee = Some(($new_feerate, used_total_fee, our_sig.clone()));
return Ok((Some(msgs::ClosingSigned {
channel_id: self.channel_id,
fee_satoshis: used_total_fee,
Expand All @@ -2809,7 +2834,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
if self.channel_outbound {
let our_max_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
if proposed_sat_per_kw > our_max_feerate {
if let Some((last_feerate, _)) = self.last_sent_closing_fee {
if let Some((last_feerate, _, _)) = self.last_sent_closing_fee {
if our_max_feerate <= last_feerate {
return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate"));
}
Expand All @@ -2819,7 +2844,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
} else {
let our_min_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
if proposed_sat_per_kw < our_min_feerate {
if let Some((last_feerate, _)) = self.last_sent_closing_fee {
if let Some((last_feerate, _, _)) = self.last_sent_closing_fee {
if our_min_feerate >= last_feerate {
return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate"));
}
Expand All @@ -2828,7 +2853,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
}
}

let our_sig = self.sign_commitment_transaction(&mut closing_tx, &msg.signature);
let our_sig = self.local_keys
.sign_closing_transaction(self.channel_value_satoshis, &funding_redeemscript, &closing_tx, &self.secp_ctx)
.map_err(|_| ChannelError::Close("External signer refused to sign closing transaction"))?;
self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &our_sig);

self.channel_state = ChannelState::ShutdownComplete as u32;
self.channel_update_count += 1;

Expand Down Expand Up @@ -3310,8 +3339,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
excess_data: Vec::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.local_keys.sign_channel_announcement(&msg, &self.secp_ctx)
.map_err(|_| ChannelError::Ignore("Signer rejected channel_announcement"))?;

Ok((msg, sig))
}
Expand Down Expand Up @@ -3855,10 +3884,11 @@ impl<ChanSigner: ChannelKeys + Writeable> Writeable for Channel<ChanSigner> {
}

match self.last_sent_closing_fee {
Some((feerate, fee)) => {
Some((feerate, fee, sig)) => {
1u8.write(writer)?;
feerate.write(writer)?;
fee.write(writer)?;
sig.write(writer)?;
},
None => 0u8.write(writer)?,
}
Expand Down Expand Up @@ -4022,7 +4052,7 @@ impl<R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R,

let last_sent_closing_fee = match <u8 as Readable<R>>::read(reader)? {
0 => None,
1 => Some((Readable::read(reader)?, Readable::read(reader)?)),
1 => Some((Readable::read(reader)?, Readable::read(reader)?, Readable::read(reader)?)),
_ => return Err(DecodeError::InvalidValue),
};

Expand Down
9 changes: 9 additions & 0 deletions lightning/src/util/enforcing_trait_impls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys};
use ln::msgs;
use chain::keysinterface::{ChannelKeys, InMemoryChannelKeys};

use std::cmp;
Expand Down Expand Up @@ -50,6 +51,14 @@ impl ChannelKeys for EnforcingChannelKeys {

Ok(self.inner.sign_remote_commitment(channel_value_satoshis, channel_funding_script, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx).unwrap())
}

fn sign_closing_transaction<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
Ok(self.inner.sign_closing_transaction(channel_value_satoshis, channel_funding_redeemscript, closing_tx, secp_ctx).unwrap())
}

fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
self.inner.sign_channel_announcement(msg, secp_ctx)
}
}

impl_writeable!(EnforcingChannelKeys, 0, {
Expand Down