use chain::transaction::OutPoint;
use ln::chan_utils;
-use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction};
+use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
use ln::msgs::UnsignedChannelAnnouncement;
+use ln::script::ShutdownScript;
use prelude::*;
-use std::collections::HashSet;
use core::sync::atomic::{AtomicUsize, Ordering};
-use std::io::Error;
+use io::{self, Error};
use ln::msgs::{DecodeError, MAX_VALUE_MSAT};
/// Information about a spendable output to a P2WSH script. See
pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 1 + chan_utils::REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH + 1;
}
+impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, {
+ (0, outpoint, required),
+ (2, per_commitment_point, required),
+ (4, to_self_delay, required),
+ (6, output, required),
+ (8, revocation_pubkey, required),
+ (10, channel_keys_id, required),
+ (12, channel_value_satoshis, required),
+});
+
/// Information about a spendable output to our "payment key". See
/// SpendableOutputDescriptor::StaticPaymentOutput for more details on how to spend this.
#[derive(Clone, Debug, PartialEq)]
// redeemscript push length.
pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 34;
}
+impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, {
+ (0, outpoint, required),
+ (2, output, required),
+ (4, channel_keys_id, required),
+ (6, channel_value_satoshis, required),
+});
/// When on-chain outputs are created by rust-lightning (which our counterparty is not able to
/// claim at any point in the future) an event is generated which you must track and be able to
#[derive(Clone, Debug, PartialEq)]
pub enum SpendableOutputDescriptor {
/// An output to a script which was provided via KeysInterface directly, either from
- /// `get_destination_script()` or `get_shutdown_pubkey()`, thus you should already know how to
- /// spend it. No secret keys are provided as rust-lightning was never given any key.
+ /// `get_destination_script()` or `get_shutdown_scriptpubkey()`, thus you should already know
+ /// how to spend it. No secret keys are provided as rust-lightning was never given any key.
/// These may include outputs from a transaction punishing our counterparty or claiming an HTLC
/// on-chain using the payment preimage or after it has timed out.
StaticOutput {
StaticPaymentOutput(StaticPaymentOutputDescriptor),
}
-impl Writeable for SpendableOutputDescriptor {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- match self {
- &SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
- 0u8.write(writer)?;
- outpoint.write(writer)?;
- output.write(writer)?;
- },
- &SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) => {
- 1u8.write(writer)?;
- descriptor.outpoint.write(writer)?;
- descriptor.per_commitment_point.write(writer)?;
- descriptor.to_self_delay.write(writer)?;
- descriptor.output.write(writer)?;
- descriptor.revocation_pubkey.write(writer)?;
- descriptor.channel_keys_id.write(writer)?;
- descriptor.channel_value_satoshis.write(writer)?;
- },
- &SpendableOutputDescriptor::StaticPaymentOutput(ref descriptor) => {
- 2u8.write(writer)?;
- descriptor.outpoint.write(writer)?;
- descriptor.output.write(writer)?;
- descriptor.channel_keys_id.write(writer)?;
- descriptor.channel_value_satoshis.write(writer)?;
- },
- }
- Ok(())
- }
-}
-
-impl Readable for SpendableOutputDescriptor {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
- match Readable::read(reader)? {
- 0u8 => Ok(SpendableOutputDescriptor::StaticOutput {
- outpoint: Readable::read(reader)?,
- output: Readable::read(reader)?,
- }),
- 1u8 => Ok(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
- outpoint: Readable::read(reader)?,
- per_commitment_point: Readable::read(reader)?,
- to_self_delay: Readable::read(reader)?,
- output: Readable::read(reader)?,
- revocation_pubkey: Readable::read(reader)?,
- channel_keys_id: Readable::read(reader)?,
- channel_value_satoshis: Readable::read(reader)?,
- })),
- 2u8 => Ok(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
- outpoint: Readable::read(reader)?,
- output: Readable::read(reader)?,
- channel_keys_id: Readable::read(reader)?,
- channel_value_satoshis: Readable::read(reader)?,
- })),
- _ => Err(DecodeError::InvalidValue),
- }
- }
-}
+impl_writeable_tlv_based_enum!(SpendableOutputDescriptor,
+ (0, StaticOutput) => {
+ (0, outpoint, required),
+ (2, output, required),
+ },
+;
+ (1, DelayedPaymentOutput),
+ (2, StaticPaymentOutput),
+);
/// A trait to sign lightning channel transactions as described in BOLT 3.
///
/// Note that the commitment number starts at (1 << 48) - 1 and counts backwards.
// TODO: return a Result so we can signal a validation error
fn release_commitment_secret(&self, idx: u64) -> [u8; 32];
+ /// Validate the counterparty's signatures on the holder commitment transaction and HTLCs.
+ ///
+ /// This is required in order for the signer to make sure that releasing a commitment
+ /// secret won't leave us without a broadcastable holder transaction.
+ /// Policy checks should be implemented in this function, including checking the amount
+ /// sent to us and checking the HTLCs.
+ fn validate_holder_commitment(&self, holder_tx: &HolderCommitmentTransaction) -> Result<(), ()>;
/// Gets the holder's channel public keys and basepoints
fn pubkeys(&self) -> &ChannelPublicKeys;
/// Gets an arbitrary identifier describing the set of keys which are provided back to you in
/// Create a signature for a counterparty's commitment transaction and associated HTLC transactions.
///
/// Note that if signing fails or is rejected, the channel will be force-closed.
+ ///
+ /// Policy checks should be implemented in this function, including checking the amount
+ /// sent to us and checking the HTLCs.
//
// TODO: Document the things someone using this interface should enforce before signing.
fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()>;
+ /// Validate the counterparty's revocation.
+ ///
+ /// This is required in order for the signer to make sure that the state has moved
+ /// forward and it is safe to sign the next counterparty commitment.
+ fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey) -> Result<(), ()>;
/// Create a signatures for a holder's commitment transaction and its claiming HTLC transactions.
/// This will only ever be called with a non-revoked commitment_tx. This will be called with the
///
/// 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(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
+ fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
/// Signs a channel announcement message with our funding key, proving it comes from one
/// of the channel participants.
/// This method should return a different value each time it is called, to avoid linking
/// on-chain funds across channels as controlled to the same user.
fn get_destination_script(&self) -> Script;
- /// Get a public key which we will send funds to (in the form of a P2WPKH output) when closing
- /// a channel.
+ /// Get a script pubkey which we will send funds to when closing a channel.
///
/// This method should return a different value each time it is called, to avoid linking
/// on-chain funds across channels as controlled to the same user.
- fn get_shutdown_pubkey(&self) -> PublicKey;
+ fn get_shutdown_scriptpubkey(&self) -> ShutdownScript;
/// Get a new set of Sign for per-channel secrets. These MUST be unique even if you
/// restarted with some stale data!
///
chan_utils::build_commitment_secret(&self.commitment_seed, idx)
}
+ fn validate_holder_commitment(&self, _holder_tx: &HolderCommitmentTransaction) -> Result<(), ()> {
+ Ok(())
+ }
+
fn pubkeys(&self) -> &ChannelPublicKeys { &self.holder_channel_pubkeys }
fn channel_keys_id(&self) -> [u8; 32] { self.channel_keys_id }
Ok((commitment_sig, htlc_sigs))
}
+ fn validate_counterparty_revocation(&self, _idx: u64, _secret: &SecretKey) -> Result<(), ()> {
+ Ok(())
+ }
+
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
Err(())
}
- fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<secp256k1::All>) -> 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(()); }
-
+ fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
-
- let sighash = hash_to_message!(&bip143::SigHashCache::new(closing_tx)
- .signature_hash(0, &channel_funding_redeemscript, self.channel_value_satoshis, SigHashType::All)[..]);
- Ok(secp_ctx.sign(&sighash, &self.funding_key))
+ Ok(closing_tx.trust().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
}
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
self.channel_value_satoshis.write(writer)?;
self.channel_keys_id.write(writer)?;
- write_tlv_fields!(writer, {}, {});
+ write_tlv_fields!(writer, {});
Ok(())
}
}
impl Readable for InMemorySigner {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
let funding_key = Readable::read(reader)?;
&htlc_base_key);
let keys_id = Readable::read(reader)?;
- read_tlv_fields!(reader, {}, {});
+ read_tlv_fields!(reader, {});
Ok(InMemorySigner {
funding_key,
self.destination_script.clone()
}
- fn get_shutdown_pubkey(&self) -> PublicKey {
- self.shutdown_pubkey.clone()
+ fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
+ ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone())
}
fn get_channel_signer(&self, _inbound: bool, channel_value_satoshis: u64) -> Self::Signer {
}
fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError> {
- InMemorySigner::read(&mut std::io::Cursor::new(reader))
+ InMemorySigner::read(&mut io::Cursor::new(reader))
}
fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {