pub(crate) const MAX_HTLCS: u16 = 483;
-pub(super) const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
-pub(super) const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
-
/// Gets the weight for an HTLC-Success transaction.
#[inline]
pub fn htlc_success_tx_weight(opt_anchors: bool) -> u64 {
+ const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
const HTLC_SUCCESS_ANCHOR_TX_WEIGHT: u64 = 706;
if opt_anchors { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT }
}
/// Gets the weight for an HTLC-Timeout transaction.
#[inline]
pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 {
+ const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
const HTLC_TIMEOUT_ANCHOR_TX_WEIGHT: u64 = 666;
if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT }
}
/// Implements the per-commitment secret storage scheme from
/// [BOLT 3](https://github.com/lightningnetwork/lightning-rfc/blob/dcbf8583976df087c79c3ce0b535311212e6812d/03-transactions.md#efficient-per-commitment-secret-storage).
///
-/// Allows us to keep track of all of the revocation secrets of counterarties in just 50*32 bytes
+/// Allows us to keep track of all of the revocation secrets of our counterparty in just 50*32 bytes
/// or so.
#[derive(Clone)]
-pub(crate) struct CounterpartyCommitmentSecrets {
+pub struct CounterpartyCommitmentSecrets {
old_secrets: [([u8; 32], u64); 49],
}
}
impl CounterpartyCommitmentSecrets {
- pub(crate) fn new() -> Self {
+ /// Creates a new empty `CounterpartyCommitmentSecrets` structure.
+ pub fn new() -> Self {
Self { old_secrets: [([0; 32], 1 << 48); 49], }
}
48
}
- pub(crate) fn get_min_seen_secret(&self) -> u64 {
+ /// Returns the minimum index of all stored secrets. Note that indexes start
+ /// at 1 << 48 and get decremented by one for each new secret.
+ pub fn get_min_seen_secret(&self) -> u64 {
//TODO This can be optimized?
let mut min = 1 << 48;
for &(_, idx) in self.old_secrets.iter() {
res
}
- pub(crate) fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), ()> {
+ /// Inserts the `secret` at `idx`. Returns `Ok(())` if the secret
+ /// was generated in accordance with BOLT 3 and is consistent with previous secrets.
+ pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), ()> {
let pos = Self::place_secret(idx);
for i in 0..pos {
let (old_secret, old_idx) = self.old_secrets[i as usize];
Ok(())
}
- /// Can only fail if idx is < get_min_seen_secret
- pub(crate) fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
+ /// Returns the secret at `idx`.
+ /// Returns `None` if `idx` is < [`CounterpartyCommitmentSecrets::get_min_seen_secret`].
+ pub fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
for i in 0..self.old_secrets.len() {
if (idx & (!((1 << i) - 1))) == self.old_secrets[i].1 {
return Some(Self::derive_secret(self.old_secrets[i].0, i as u8, idx))
///
/// This class can be used inside a signer implementation to generate a signature given the relevant
/// secret key.
+#[derive(Clone, Hash, PartialEq)]
pub struct ClosingTransaction {
to_holder_value_sat: u64,
to_counterparty_value_sat: u64,
if let &Some(ref b_htlcout) = b {
a_htlcout.cltv_expiry.cmp(&b_htlcout.cltv_expiry)
// Note that due to hash collisions, we have to have a fallback comparison
- // here for fuzztarget mode (otherwise at least chanmon_fail_consistency
+ // here for fuzzing mode (otherwise at least chanmon_fail_consistency
// may fail)!
.then(a_htlcout.payment_hash.0.cmp(&b_htlcout.payment_hash.0))
// For non-HTLC outputs, if they're copying our SPK we don't really care if we
/// which HTLCOutputInCommitment::transaction_output_index.is_some()).
///
/// The returned Vec has one entry for each HTLC, and in the same order.
+ ///
+ /// This function is only valid in the holder commitment context, it always uses SigHashType::All.
pub fn get_htlc_sigs<T: secp256k1::Signing>(&self, htlc_base_key: &SecretKey, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1<T>) -> Result<Vec<Signature>, ()> {
let inner = self.inner;
let keys = &inner.keys;
let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
+ let sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All };
+
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
htlc_tx.input[0].witness.push(Vec::new());
htlc_tx.input[0].witness.push(counterparty_signature.serialize_der().to_vec());
htlc_tx.input[0].witness.push(signature.serialize_der().to_vec());
- htlc_tx.input[0].witness[1].push(SigHashType::All as u8);
+ htlc_tx.input[0].witness[1].push(sighashtype as u8);
htlc_tx.input[0].witness[2].push(SigHashType::All as u8);
if this_htlc.offered {
use chain::keysinterface::{KeysInterface, BaseSign};
use bitcoin::Network;
use ln::PaymentHash;
+ use bitcoin::hashes::hex::ToHex;
#[test]
fn test_anchors() {
assert_eq!(tx.built.transaction.output.len(), 3);
assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh());
assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh());
+ assert_eq!(get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+ "002085cf52e41ba7c099a39df504e7b61f6de122971ceb53b06731876eaeb85e8dc5");
+ assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+ "002049f0736bb335c61a04d2623a24df878a7592a3c51fa7258d41b2c85318265e73");
// Generate broadcaster output and received and offered HTLC outputs, with anchors
channel_parameters.opt_anchors = Some(());
assert_eq!(tx.built.transaction.output.len(), 5);
assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh());
assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh());
+ assert_eq!(get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+ "002067114123af3f95405bae4fd930fc95de03e3c86baaee8b2dd29b43dd26cf613c");
+ assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+ "0020a06e3b0d4fcf704f2b9c41e16a70099e39989466c3142b8573a1154542f28f57");
}
#[test]