Skip to content

Commit 835a064

Browse files
committed
Struct-ify SpendableOutputDescriptor entries relevant to channels
Both SpendableOutputDescriptor::DynamicOutputP2WSH and SpendableOutputDescriptor::StaticOutputCounterpartyPayment are relevant only in the context of a given channel, making them candidates for being passed into helper functions in `InMemoryChannelKeys`. This moves them into their own structs so that they can later be used standalone.
1 parent aef598f commit 835a064

File tree

5 files changed

+105
-76
lines changed

5 files changed

+105
-76
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
4343
use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
4444
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
4545
use chain::transaction::{OutPoint, TransactionData};
46-
use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys, KeysInterface};
46+
use chain::keysinterface::{SpendableOutputDescriptor, StaticCounterpartyPaymentOutputDescriptor, DynamicP2WSHOutputDescriptor, ChannelKeys, KeysInterface};
4747
use util::logger::Logger;
4848
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48};
4949
use util::byte_utils;
@@ -2201,24 +2201,24 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
22012201
break;
22022202
} else if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script {
22032203
if broadcasted_holder_revokable_script.0 == outp.script_pubkey {
2204-
spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
2204+
spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH(DynamicP2WSHOutputDescriptor {
22052205
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
22062206
per_commitment_point: broadcasted_holder_revokable_script.1,
22072207
to_self_delay: self.on_holder_tx_csv,
22082208
output: outp.clone(),
22092209
revocation_pubkey: broadcasted_holder_revokable_script.2.clone(),
22102210
key_derivation_params: self.key_derivation_params,
22112211
channel_value_satoshis: self.channel_value_satoshis,
2212-
});
2212+
}));
22132213
break;
22142214
}
22152215
} else if self.counterparty_payment_script == outp.script_pubkey {
2216-
spendable_output = Some(SpendableOutputDescriptor::StaticOutputCounterpartyPayment {
2216+
spendable_output = Some(SpendableOutputDescriptor::StaticOutputCounterpartyPayment(StaticCounterpartyPaymentOutputDescriptor {
22172217
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
22182218
output: outp.clone(),
22192219
key_derivation_params: self.key_derivation_params,
22202220
channel_value_satoshis: self.channel_value_satoshis,
2221-
});
2221+
}));
22222222
break;
22232223
} else if outp.script_pubkey == self.shutdown_script {
22242224
spendable_output = Some(SpendableOutputDescriptor::StaticOutput {

lightning/src/chain/keysinterface.rs

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,57 @@ use std::sync::atomic::{AtomicUsize, Ordering};
4040
use std::io::Error;
4141
use ln::msgs::DecodeError;
4242

43+
/// Information about a spendable output to a P2WSH script. See
44+
/// SpendableOutputDescriptor::DynamicOutputP2WSH for more details on how to spend this.
45+
#[derive(Clone, Debug, PartialEq)]
46+
pub struct DynamicP2WSHOutputDescriptor {
47+
/// The outpoint which is spendable
48+
pub outpoint: OutPoint,
49+
/// Per commitment point to derive delayed_payment_key by key holder
50+
pub per_commitment_point: PublicKey,
51+
/// The nSequence value which must be set in the spending input to satisfy the OP_CSV in
52+
/// the witness_script.
53+
pub to_self_delay: u16,
54+
/// The output which is referenced by the given outpoint
55+
pub output: TxOut,
56+
/// The revocation_pubkey used to derive witnessScript
57+
pub revocation_pubkey: PublicKey,
58+
/// Arbitrary identification information returned by a call to
59+
/// `ChannelKeys::key_derivation_params()`. This may be useful in re-deriving keys used in
60+
/// the channel to spend the output.
61+
pub key_derivation_params: (u64, u64),
62+
/// The value of the channel which this output originated from, possibly indirectly.
63+
pub channel_value_satoshis: u64,
64+
}
65+
impl DynamicP2WSHOutputDescriptor {
66+
/// The maximum length a well-formed witness spending one of these should have.
67+
// Calculated as 1 byte legnth + 73 byte signature, 1 byte empty vec push, 1 byte length plus
68+
// redeemscript push length.
69+
pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 1 + chan_utils::REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH + 1;
70+
}
71+
72+
/// Information about a spendable output to our "payment key". See
73+
/// SpendableOutputDescriptor::StaticOutputCounterpartyPayment for more details on how to spend this.
74+
#[derive(Clone, Debug, PartialEq)]
75+
pub struct StaticCounterpartyPaymentOutputDescriptor {
76+
/// The outpoint which is spendable
77+
pub outpoint: OutPoint,
78+
/// The output which is reference by the given outpoint
79+
pub output: TxOut,
80+
/// Arbitrary identification information returned by a call to
81+
/// `ChannelKeys::key_derivation_params()`. This may be useful in re-deriving keys used in
82+
/// the channel to spend the output.
83+
pub key_derivation_params: (u64, u64),
84+
/// The value of the channel which this transactions spends.
85+
pub channel_value_satoshis: u64,
86+
}
87+
impl StaticCounterpartyPaymentOutputDescriptor {
88+
/// The maximum length a well-formed witness spending one of these should have.
89+
// Calculated as 1 byte legnth + 73 byte signature, 1 byte empty vec push, 1 byte length plus
90+
// redeemscript push length.
91+
pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 34;
92+
}
93+
4394
/// When on-chain outputs are created by rust-lightning (which our counterparty is not able to
4495
/// claim at any point in the future) an event is generated which you must track and be able to
4596
/// spend on-chain. The information needed to do this is provided in this enum, including the
@@ -88,44 +139,15 @@ pub enum SpendableOutputDescriptor {
88139
/// chan_utils::get_revokeable_redeemscript.
89140
//
90141
// TODO: we need to expose utility methods in KeyManager to do all the relevant derivation.
91-
DynamicOutputP2WSH {
92-
/// The outpoint which is spendable
93-
outpoint: OutPoint,
94-
/// Per commitment point to derive delayed_payment_key by key holder
95-
per_commitment_point: PublicKey,
96-
/// The nSequence value which must be set in the spending input to satisfy the OP_CSV in
97-
/// the witness_script.
98-
to_self_delay: u16,
99-
/// The output which is referenced by the given outpoint
100-
output: TxOut,
101-
/// The revocation_pubkey used to derive witnessScript
102-
revocation_pubkey: PublicKey,
103-
/// Arbitrary identification information returned by a call to
104-
/// `ChannelKeys::key_derivation_params()`. This may be useful in re-deriving keys used in
105-
/// the channel to spend the output.
106-
key_derivation_params: (u64, u64),
107-
/// The value of the channel which this output originated from, possibly indirectly.
108-
channel_value_satoshis: u64,
109-
},
142+
DynamicOutputP2WSH(DynamicP2WSHOutputDescriptor),
110143
/// An output to a P2WPKH, spendable exclusively by our payment key (ie the private key which
111144
/// corresponds to the public key in ChannelKeys::pubkeys().payment_point).
112145
/// The witness in the spending input, is, thus, simply:
113146
/// <BIP 143 signature> <payment key>
114147
///
115148
/// These are generally the result of our counterparty having broadcast the current state,
116149
/// allowing us to claim the non-HTLC-encumbered outputs immediately.
117-
StaticOutputCounterpartyPayment {
118-
/// The outpoint which is spendable
119-
outpoint: OutPoint,
120-
/// The output which is reference by the given outpoint
121-
output: TxOut,
122-
/// Arbitrary identification information returned by a call to
123-
/// `ChannelKeys::key_derivation_params()`. This may be useful in re-deriving keys used in
124-
/// the channel to spend the output.
125-
key_derivation_params: (u64, u64),
126-
/// The value of the channel which this transactions spends.
127-
channel_value_satoshis: u64,
128-
}
150+
StaticOutputCounterpartyPayment(StaticCounterpartyPaymentOutputDescriptor),
129151
}
130152

131153
impl Writeable for SpendableOutputDescriptor {
@@ -136,24 +158,24 @@ impl Writeable for SpendableOutputDescriptor {
136158
outpoint.write(writer)?;
137159
output.write(writer)?;
138160
},
139-
&SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref revocation_pubkey, ref key_derivation_params, channel_value_satoshis } => {
161+
&SpendableOutputDescriptor::DynamicOutputP2WSH(ref descriptor) => {
140162
1u8.write(writer)?;
141-
outpoint.write(writer)?;
142-
per_commitment_point.write(writer)?;
143-
to_self_delay.write(writer)?;
144-
output.write(writer)?;
145-
revocation_pubkey.write(writer)?;
146-
key_derivation_params.0.write(writer)?;
147-
key_derivation_params.1.write(writer)?;
148-
channel_value_satoshis.write(writer)?;
163+
descriptor.outpoint.write(writer)?;
164+
descriptor.per_commitment_point.write(writer)?;
165+
descriptor.to_self_delay.write(writer)?;
166+
descriptor.output.write(writer)?;
167+
descriptor.revocation_pubkey.write(writer)?;
168+
descriptor.key_derivation_params.0.write(writer)?;
169+
descriptor.key_derivation_params.1.write(writer)?;
170+
descriptor.channel_value_satoshis.write(writer)?;
149171
},
150-
&SpendableOutputDescriptor::StaticOutputCounterpartyPayment { ref outpoint, ref output, ref key_derivation_params, channel_value_satoshis } => {
172+
&SpendableOutputDescriptor::StaticOutputCounterpartyPayment(ref descriptor) => {
151173
2u8.write(writer)?;
152-
outpoint.write(writer)?;
153-
output.write(writer)?;
154-
key_derivation_params.0.write(writer)?;
155-
key_derivation_params.1.write(writer)?;
156-
channel_value_satoshis.write(writer)?;
174+
descriptor.outpoint.write(writer)?;
175+
descriptor.output.write(writer)?;
176+
descriptor.key_derivation_params.0.write(writer)?;
177+
descriptor.key_derivation_params.1.write(writer)?;
178+
descriptor.channel_value_satoshis.write(writer)?;
157179
},
158180
}
159181
Ok(())
@@ -167,21 +189,21 @@ impl Readable for SpendableOutputDescriptor {
167189
outpoint: Readable::read(reader)?,
168190
output: Readable::read(reader)?,
169191
}),
170-
1u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WSH {
192+
1u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WSH(DynamicP2WSHOutputDescriptor {
171193
outpoint: Readable::read(reader)?,
172194
per_commitment_point: Readable::read(reader)?,
173195
to_self_delay: Readable::read(reader)?,
174196
output: Readable::read(reader)?,
175197
revocation_pubkey: Readable::read(reader)?,
176198
key_derivation_params: (Readable::read(reader)?, Readable::read(reader)?),
177199
channel_value_satoshis: Readable::read(reader)?,
178-
}),
179-
2u8 => Ok(SpendableOutputDescriptor::StaticOutputCounterpartyPayment {
200+
})),
201+
2u8 => Ok(SpendableOutputDescriptor::StaticOutputCounterpartyPayment(StaticCounterpartyPaymentOutputDescriptor {
180202
outpoint: Readable::read(reader)?,
181203
output: Readable::read(reader)?,
182204
key_derivation_params: (Readable::read(reader)?, Readable::read(reader)?),
183205
channel_value_satoshis: Readable::read(reader)?,
184-
}),
206+
})),
185207
_ => Err(DecodeError::InvalidValue),
186208
}
187209
}

lightning/src/ln/chan_utils.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,11 +384,16 @@ impl TxCreationKeys {
384384
}
385385
}
386386

387+
/// The maximum length of a script returned by get_revokeable_redeemscript.
388+
// Calculated as 6 bytes of opcodes, 1 byte push plus 2 bytes for contest_delay, and two public
389+
// keys of 33 bytes (+ 1 push).
390+
pub const REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH: usize = 6 + 3 + 34*2;
391+
387392
/// A script either spendable by the revocation
388393
/// key or the broadcaster_delayed_payment_key and satisfying the relative-locktime OP_CSV constrain.
389394
/// Encumbering a `to_holder` output on a commitment transaction or 2nd-stage HTLC transactions.
390395
pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u16, broadcaster_delayed_payment_key: &PublicKey) -> Script {
391-
Builder::new().push_opcode(opcodes::all::OP_IF)
396+
let res = Builder::new().push_opcode(opcodes::all::OP_IF)
392397
.push_slice(&revocation_key.serialize())
393398
.push_opcode(opcodes::all::OP_ELSE)
394399
.push_int(contest_delay as i64)
@@ -397,7 +402,9 @@ pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u1
397402
.push_slice(&broadcaster_delayed_payment_key.serialize())
398403
.push_opcode(opcodes::all::OP_ENDIF)
399404
.push_opcode(opcodes::all::OP_CHECKSIG)
400-
.into_script()
405+
.into_script();
406+
debug_assert!(res.len() <= REVOKEABLE_REDEEMSCRIPT_MAX_LENGTH);
407+
res
401408
}
402409

403410
#[derive(Clone, PartialEq)]

lightning/src/ln/functional_tests.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4662,17 +4662,17 @@ macro_rules! check_spendable_outputs {
46624662
Event::SpendableOutputs { ref outputs } => {
46634663
for outp in outputs {
46644664
match *outp {
4665-
SpendableOutputDescriptor::StaticOutputCounterpartyPayment { ref outpoint, ref output, ref key_derivation_params, channel_value_satoshis } => {
4666-
assert_eq!(channel_value_satoshis, $chan_value);
4665+
SpendableOutputDescriptor::StaticOutputCounterpartyPayment(ref descriptor) => {
4666+
assert_eq!(descriptor.channel_value_satoshis, $chan_value);
46674667
let input = TxIn {
4668-
previous_output: outpoint.into_bitcoin_outpoint(),
4668+
previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
46694669
script_sig: Script::new(),
46704670
sequence: 0,
46714671
witness: Vec::new(),
46724672
};
46734673
let outp = TxOut {
46744674
script_pubkey: Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(),
4675-
value: output.value,
4675+
value: descriptor.output.value,
46764676
};
46774677
let mut spend_tx = Transaction {
46784678
version: 2,
@@ -4682,27 +4682,27 @@ macro_rules! check_spendable_outputs {
46824682
};
46834683
spend_tx.output[0].value -= (spend_tx.get_weight() + 2 + 1 + 73 + 35 + 3) as u64 / 4; // (Max weight + 3 (to round up)) / 4
46844684
let secp_ctx = Secp256k1::new();
4685-
let keys = $keysinterface.derive_channel_keys($chan_value, key_derivation_params.0, key_derivation_params.1);
4685+
let keys = $keysinterface.derive_channel_keys($chan_value, descriptor.key_derivation_params.0, descriptor.key_derivation_params.1);
46864686
let remotepubkey = keys.pubkeys().payment_point;
46874687
let witness_script = Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Testnet).script_pubkey();
4688-
let sighash = Message::from_slice(&bip143::SigHashCache::new(&spend_tx).signature_hash(0, &witness_script, output.value, SigHashType::All)[..]).unwrap();
4688+
let sighash = Message::from_slice(&bip143::SigHashCache::new(&spend_tx).signature_hash(0, &witness_script, descriptor.output.value, SigHashType::All)[..]).unwrap();
46894689
let remotesig = secp_ctx.sign(&sighash, &keys.inner.payment_key);
46904690
spend_tx.input[0].witness.push(remotesig.serialize_der().to_vec());
46914691
spend_tx.input[0].witness[0].push(SigHashType::All as u8);
46924692
spend_tx.input[0].witness.push(remotepubkey.serialize().to_vec());
46934693
txn.push(spend_tx);
46944694
},
4695-
SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref revocation_pubkey, ref key_derivation_params, channel_value_satoshis } => {
4696-
assert_eq!(channel_value_satoshis, $chan_value);
4695+
SpendableOutputDescriptor::DynamicOutputP2WSH(ref descriptor) => {
4696+
assert_eq!(descriptor.channel_value_satoshis, $chan_value);
46974697
let input = TxIn {
4698-
previous_output: outpoint.into_bitcoin_outpoint(),
4698+
previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
46994699
script_sig: Script::new(),
4700-
sequence: *to_self_delay as u32,
4700+
sequence: descriptor.to_self_delay as u32,
47014701
witness: Vec::new(),
47024702
};
47034703
let outp = TxOut {
47044704
script_pubkey: Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(),
4705-
value: output.value,
4705+
value: descriptor.output.value,
47064706
};
47074707
let mut spend_tx = Transaction {
47084708
version: 2,
@@ -4711,13 +4711,13 @@ macro_rules! check_spendable_outputs {
47114711
output: vec![outp],
47124712
};
47134713
let secp_ctx = Secp256k1::new();
4714-
let keys = $keysinterface.derive_channel_keys($chan_value, key_derivation_params.0, key_derivation_params.1);
4715-
if let Ok(delayed_payment_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &keys.inner.delayed_payment_base_key) {
4714+
let keys = $keysinterface.derive_channel_keys($chan_value, descriptor.key_derivation_params.0, descriptor.key_derivation_params.1);
4715+
if let Ok(delayed_payment_key) = chan_utils::derive_private_key(&secp_ctx, &descriptor.per_commitment_point, &keys.inner.delayed_payment_base_key) {
47164716

47174717
let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key);
4718-
let witness_script = chan_utils::get_revokeable_redeemscript(revocation_pubkey, *to_self_delay, &delayed_payment_pubkey);
4718+
let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey);
47194719
spend_tx.output[0].value -= (spend_tx.get_weight() + 2 + 1 + 73 + 1 + witness_script.len() + 1 + 3) as u64 / 4; // (Max weight + 3 (to round up)) / 4
4720-
let sighash = Message::from_slice(&bip143::SigHashCache::new(&spend_tx).signature_hash(0, &witness_script, output.value, SigHashType::All)[..]).unwrap();
4720+
let sighash = Message::from_slice(&bip143::SigHashCache::new(&spend_tx).signature_hash(0, &witness_script, descriptor.output.value, SigHashType::All)[..]).unwrap();
47214721
let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key);
47224722
spend_tx.input[0].witness.push(local_delayedsig.serialize_der().to_vec());
47234723
spend_tx.input[0].witness[0].push(SigHashType::All as u8);

lightning/src/util/macro_logger.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,11 @@ impl<'a> std::fmt::Display for DebugSpendable<'a> {
138138
&SpendableOutputDescriptor::StaticOutput { ref outpoint, .. } => {
139139
write!(f, "StaticOutput {}:{} marked for spending", outpoint.txid, outpoint.index)?;
140140
}
141-
&SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, .. } => {
142-
write!(f, "DynamicOutputP2WSH {}:{} marked for spending", outpoint.txid, outpoint.index)?;
141+
&SpendableOutputDescriptor::DynamicOutputP2WSH(ref descriptor) => {
142+
write!(f, "DynamicOutputP2WSH {}:{} marked for spending", descriptor.outpoint.txid, descriptor.outpoint.index)?;
143143
}
144-
&SpendableOutputDescriptor::StaticOutputCounterpartyPayment { ref outpoint, .. } => {
145-
write!(f, "DynamicOutputP2WPKH {}:{} marked for spending", outpoint.txid, outpoint.index)?;
144+
&SpendableOutputDescriptor::StaticOutputCounterpartyPayment(ref descriptor) => {
145+
write!(f, "DynamicOutputP2WPKH {}:{} marked for spending", descriptor.outpoint.txid, descriptor.outpoint.index)?;
146146
}
147147
}
148148
Ok(())

0 commit comments

Comments
 (0)