mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
construct funding redeem script in signer
This commit is contained in:
parent
9c572a98fb
commit
6200302dc7
6 changed files with 62 additions and 22 deletions
|
@ -158,6 +158,7 @@ impl KeysInterface for KeyProvider {
|
|||
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],
|
||||
remote_funding_pubkey: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -257,6 +257,7 @@ impl KeysInterface for KeyProvider {
|
|||
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, 4, ctr]).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, 5, 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],
|
||||
remote_funding_pubkey: None,
|
||||
}
|
||||
} else {
|
||||
InMemoryChannelKeys {
|
||||
|
@ -266,6 +267,7 @@ impl KeysInterface for KeyProvider {
|
|||
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, 10, ctr]).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, 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],
|
||||
remote_funding_pubkey: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use util::logger::Logger;
|
|||
use util::ser::Writeable;
|
||||
|
||||
use ln::chan_utils;
|
||||
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
|
||||
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript};
|
||||
use ln::msgs;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
@ -142,7 +142,7 @@ 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_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>), ()>;
|
||||
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, feerate_per_kw: 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.
|
||||
///
|
||||
|
@ -157,6 +157,12 @@ pub trait ChannelKeys : Send {
|
|||
/// 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, ()>;
|
||||
|
||||
/// Set the remote funding key. This is done immediately on incoming channels
|
||||
/// and as soon as the channel is accepted on outgoing channels.
|
||||
///
|
||||
/// Will be called before any signatures are applied.
|
||||
fn set_remote_funding_pubkey(&mut self, key: &PublicKey);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -174,6 +180,8 @@ pub struct InMemoryChannelKeys {
|
|||
pub htlc_base_key: SecretKey,
|
||||
/// Commitment seed
|
||||
pub commitment_seed: [u8; 32],
|
||||
/// Remote funding pubkey
|
||||
pub remote_funding_pubkey: Option<PublicKey>,
|
||||
}
|
||||
|
||||
impl ChannelKeys for InMemoryChannelKeys {
|
||||
|
@ -184,8 +192,13 @@ 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_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>), ()> {
|
||||
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, 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 funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
|
||||
let remote_funding_pubkey = self.remote_funding_pubkey.as_ref().expect("must set remote funding key before signing");
|
||||
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, remote_funding_pubkey);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -222,6 +235,11 @@ impl ChannelKeys for InMemoryChannelKeys {
|
|||
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
|
||||
Ok(secp_ctx.sign(&msghash, &self.funding_key))
|
||||
}
|
||||
|
||||
fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
|
||||
assert!(self.remote_funding_pubkey.is_none(), "Already set remote funding key");
|
||||
self.remote_funding_pubkey = Some(*key);
|
||||
}
|
||||
}
|
||||
|
||||
impl_writeable!(InMemoryChannelKeys, 0, {
|
||||
|
@ -230,7 +248,8 @@ impl_writeable!(InMemoryChannelKeys, 0, {
|
|||
payment_base_key,
|
||||
delayed_payment_base_key,
|
||||
htlc_base_key,
|
||||
commitment_seed
|
||||
commitment_seed,
|
||||
remote_funding_pubkey
|
||||
});
|
||||
|
||||
/// Simple KeysInterface implementor that takes a 32-byte seed for use as a BIP 32 extended key
|
||||
|
@ -379,6 +398,7 @@ impl KeysInterface for KeysManager {
|
|||
delayed_payment_base_key,
|
||||
htlc_base_key,
|
||||
commitment_seed,
|
||||
remote_funding_pubkey: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -255,6 +255,22 @@ pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKey
|
|||
get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
|
||||
}
|
||||
|
||||
/// Gets the redeemscript for a funding output from the two funding public keys.
|
||||
/// Note that the order of funding public keys does not matter.
|
||||
pub fn make_funding_redeemscript(a: &PublicKey, b: &PublicKey) -> Script {
|
||||
let our_funding_key = a.serialize();
|
||||
let their_funding_key = b.serialize();
|
||||
|
||||
let builder = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2);
|
||||
if our_funding_key[..] < their_funding_key[..] {
|
||||
builder.push_slice(&our_funding_key)
|
||||
.push_slice(&their_funding_key)
|
||||
} else {
|
||||
builder.push_slice(&their_funding_key)
|
||||
.push_slice(&our_funding_key)
|
||||
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
|
||||
}
|
||||
|
||||
/// panics if htlc.transaction_output_index.is_none()!
|
||||
pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
|
||||
let mut txins: Vec<TxIn> = Vec::new();
|
||||
|
|
|
@ -20,7 +20,7 @@ use ln::msgs;
|
|||
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
|
||||
use ln::channelmonitor::ChannelMonitor;
|
||||
use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
|
||||
use ln::chan_utils::{LocalCommitmentTransaction,TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
|
||||
use ln::chan_utils::{LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript};
|
||||
use ln::chan_utils;
|
||||
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
|
||||
use chain::transaction::OutPoint;
|
||||
|
@ -545,7 +545,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
/// 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<ChanKeySigner = ChanSigner>>, their_node_id: PublicKey, their_features: InitFeatures, 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 chan_keys = keys_provider.get_channel_keys(true);
|
||||
chan_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
|
||||
let mut local_config = (*config).channel_options.clone();
|
||||
|
||||
if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
|
||||
|
@ -1111,16 +1112,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
/// pays to get_funding_redeemscript().to_v0_p2wsh()).
|
||||
/// 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 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)
|
||||
.push_slice(&their_funding_key)
|
||||
} else {
|
||||
builder.push_slice(&their_funding_key)
|
||||
.push_slice(&our_funding_key)
|
||||
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
|
||||
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key());
|
||||
let their_funding_key = self.their_funding_pubkey.expect("get_funding_redeemscript only allowed after accept_channel");
|
||||
make_funding_redeemscript(&our_funding_key, &their_funding_key)
|
||||
}
|
||||
|
||||
/// Builds the htlc-success or htlc-timeout transaction which spends a given HTLC output
|
||||
|
@ -1407,6 +1401,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
self.channel_monitor.set_basic_channel_info(&msg.htlc_basepoint, &msg.delayed_payment_basepoint, msg.to_self_delay, funding_redeemscript, self.channel_value_satoshis, obscure_factor);
|
||||
|
||||
self.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32;
|
||||
self.local_keys.set_remote_funding_pubkey(&msg.funding_pubkey);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1425,7 +1420,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
|
||||
let remote_keys = self.build_remote_transaction_keys()?;
|
||||
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
|
||||
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
|
||||
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
|
||||
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0;
|
||||
|
||||
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
|
||||
|
@ -2645,6 +2640,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
|
||||
self.channel_state |= ChannelState::LocalShutdownSent as u32;
|
||||
self.channel_update_count += 1;
|
||||
|
||||
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
|
||||
}
|
||||
|
||||
|
@ -3151,7 +3147,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), ChannelError> {
|
||||
let remote_keys = self.build_remote_transaction_keys()?;
|
||||
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
|
||||
Ok((self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
|
||||
Ok((self.local_keys.sign_remote_commitment(self.channel_value_satoshis, self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
|
||||
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0, remote_initial_commitment_tx))
|
||||
}
|
||||
|
||||
|
@ -3459,7 +3455,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
|
|||
htlcs.push(htlc);
|
||||
}
|
||||
|
||||
let res = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, self.our_to_self_delay, &self.secp_ctx)
|
||||
let res = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, self.our_to_self_delay, &self.secp_ctx)
|
||||
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?;
|
||||
signature = res.0;
|
||||
htlc_signatures = res.1;
|
||||
|
@ -4131,6 +4127,7 @@ mod tests {
|
|||
// These aren't set in the test vectors:
|
||||
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],
|
||||
remote_funding_pubkey: None,
|
||||
};
|
||||
assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
|
||||
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
|
||||
|
|
|
@ -9,7 +9,7 @@ use bitcoin::blockdata::transaction::Transaction;
|
|||
use bitcoin::blockdata::script::Script;
|
||||
|
||||
use secp256k1;
|
||||
use secp256k1::key::SecretKey;
|
||||
use secp256k1::key::{SecretKey, PublicKey};
|
||||
use secp256k1::{Secp256k1, Signature};
|
||||
|
||||
/// Enforces some rules on ChannelKeys calls. Eventually we will probably want to expose a variant
|
||||
|
@ -35,7 +35,7 @@ impl ChannelKeys for EnforcingChannelKeys {
|
|||
fn htlc_base_key(&self) -> &SecretKey { self.inner.htlc_base_key() }
|
||||
fn commitment_seed(&self) -> &[u8; 32] { self.inner.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, 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 { panic!(); }
|
||||
let obscured_commitment_transaction_number = (commitment_tx.lock_time & 0xffffff) as u64 | ((commitment_tx.input[0].sequence as u64 & 0xffffff) << 3*8);
|
||||
|
||||
|
@ -49,7 +49,7 @@ impl ChannelKeys for EnforcingChannelKeys {
|
|||
commitment_data.1 = cmp::max(commitment_number, commitment_data.1)
|
||||
}
|
||||
|
||||
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())
|
||||
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, 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, ()> {
|
||||
|
@ -59,6 +59,10 @@ impl ChannelKeys for EnforcingChannelKeys {
|
|||
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)
|
||||
}
|
||||
|
||||
fn set_remote_funding_pubkey(&mut self, key: &PublicKey) {
|
||||
self.inner.set_remote_funding_pubkey(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl_writeable!(EnforcingChannelKeys, 0, {
|
||||
|
|
Loading…
Add table
Reference in a new issue