Skip to content

Commit 20cd856

Browse files
committed
Remove OptionalField and move shutdown_scriptpubkey into TLV stream
As pointed out in lightning/bolts@6656b70, we can move the `shutdown_scriptpubkey` field into the TLV streams of `OpenChannel` and `AcceptChannel` without affecting the resulting encoding. We use `WithoutLength` encoding here to ensure that we do not encode a length prefix along with `Script` as is normally the case.
1 parent 16d0f2f commit 20cd856

File tree

5 files changed

+40
-83
lines changed

5 files changed

+40
-83
lines changed

lightning/src/ln/channel.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use bitcoin::secp256k1;
2525
use crate::ln::{PaymentPreimage, PaymentHash};
2626
use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
2727
use crate::ln::msgs;
28-
use crate::ln::msgs::{DecodeError, OptionalField};
28+
use crate::ln::msgs::DecodeError;
2929
use crate::ln::script::{self, ShutdownScript};
3030
use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
3131
use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
@@ -1314,7 +1314,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
13141314

13151315
let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
13161316
match &msg.shutdown_scriptpubkey {
1317-
&OptionalField::Present(ref script) => {
1317+
&Some(ref script) => {
13181318
// Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
13191319
if script.len() == 0 {
13201320
None
@@ -1326,7 +1326,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
13261326
}
13271327
},
13281328
// Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
1329-
&OptionalField::Absent => {
1329+
&None => {
13301330
return Err(ChannelError::Close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned()));
13311331
}
13321332
}
@@ -2191,7 +2191,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
21912191

21922192
let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
21932193
match &msg.shutdown_scriptpubkey {
2194-
&OptionalField::Present(ref script) => {
2194+
&Some(ref script) => {
21952195
// Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
21962196
if script.len() == 0 {
21972197
None
@@ -2203,7 +2203,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
22032203
}
22042204
},
22052205
// Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
2206-
&OptionalField::Absent => {
2206+
&None => {
22072207
return Err(ChannelError::Close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned()));
22082208
}
22092209
}
@@ -5318,7 +5318,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
53185318
htlc_basepoint: keys.htlc_basepoint,
53195319
first_per_commitment_point,
53205320
channel_flags: if self.config.announced_channel {1} else {0},
5321-
shutdown_scriptpubkey: OptionalField::Present(match &self.shutdown_scriptpubkey {
5321+
shutdown_scriptpubkey: Some(match &self.shutdown_scriptpubkey {
53225322
Some(script) => script.clone().into_inner(),
53235323
None => Builder::new().into_script(),
53245324
}),
@@ -5384,7 +5384,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
53845384
delayed_payment_basepoint: keys.delayed_payment_basepoint,
53855385
htlc_basepoint: keys.htlc_basepoint,
53865386
first_per_commitment_point,
5387-
shutdown_scriptpubkey: OptionalField::Present(match &self.shutdown_scriptpubkey {
5387+
shutdown_scriptpubkey: Some(match &self.shutdown_scriptpubkey {
53885388
Some(script) => script.clone().into_inner(),
53895389
None => Builder::new().into_script(),
53905390
}),

lightning/src/ln/msgs.rs

+10-70
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ pub struct OpenChannel {
199199
pub first_per_commitment_point: PublicKey,
200200
/// The channel flags to be used
201201
pub channel_flags: u8,
202-
/// Optionally, a request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close
203-
pub shutdown_scriptpubkey: OptionalField<Script>,
202+
/// A request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close
203+
pub shutdown_scriptpubkey: Option<Script>,
204204
/// The channel type that this channel will represent
205205
///
206206
/// If this is `None`, we derive the channel type from the intersection of our
@@ -241,8 +241,8 @@ pub struct AcceptChannel {
241241
pub htlc_basepoint: PublicKey,
242242
/// The first to-be-broadcast-by-sender transaction's per commitment point
243243
pub first_per_commitment_point: PublicKey,
244-
/// Optionally, a request to pre-set the to-sender output's scriptPubkey for when we collaboratively close
245-
pub shutdown_scriptpubkey: OptionalField<Script>,
244+
/// A request to pre-set the to-sender output's scriptPubkey for when we collaboratively close
245+
pub shutdown_scriptpubkey: Option<Script>,
246246
/// The channel type that this channel will represent.
247247
///
248248
/// If this is `None`, we derive the channel type from the intersection of
@@ -946,20 +946,6 @@ pub struct CommitmentUpdate {
946946
pub commitment_signed: CommitmentSigned,
947947
}
948948

949-
/// Messages could have optional fields to use with extended features
950-
/// As we wish to serialize these differently from `Option<T>`s (`Options` get a tag byte, but
951-
/// [`OptionalField`] simply gets `Present` if there are enough bytes to read into it), we have a
952-
/// separate enum type for them.
953-
///
954-
/// This is not exported to bindings users due to a free generic in `T`
955-
#[derive(Clone, Debug, PartialEq, Eq)]
956-
pub enum OptionalField<T> {
957-
/// Optional field is included in message
958-
Present(T),
959-
/// Optional field is absent in message
960-
Absent
961-
}
962-
963949
/// A trait to describe an object which can receive channel messages.
964950
///
965951
/// Messages MAY be called in parallel when they originate from different `their_node_ids`, however
@@ -1255,52 +1241,6 @@ impl From<io::Error> for DecodeError {
12551241
}
12561242
}
12571243

1258-
impl Writeable for OptionalField<Script> {
1259-
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1260-
match *self {
1261-
OptionalField::Present(ref script) => {
1262-
// Note that Writeable for script includes the 16-bit length tag for us
1263-
script.write(w)?;
1264-
},
1265-
OptionalField::Absent => {}
1266-
}
1267-
Ok(())
1268-
}
1269-
}
1270-
1271-
impl Readable for OptionalField<Script> {
1272-
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1273-
match <u16 as Readable>::read(r) {
1274-
Ok(len) => {
1275-
let mut buf = vec![0; len as usize];
1276-
r.read_exact(&mut buf)?;
1277-
Ok(OptionalField::Present(Script::from(buf)))
1278-
},
1279-
Err(DecodeError::ShortRead) => Ok(OptionalField::Absent),
1280-
Err(e) => Err(e)
1281-
}
1282-
}
1283-
}
1284-
1285-
impl Writeable for OptionalField<u64> {
1286-
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1287-
match *self {
1288-
OptionalField::Present(ref value) => {
1289-
value.write(w)?;
1290-
},
1291-
OptionalField::Absent => {}
1292-
}
1293-
Ok(())
1294-
}
1295-
}
1296-
1297-
impl Readable for OptionalField<u64> {
1298-
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
1299-
let value: u64 = Readable::read(r)?;
1300-
Ok(OptionalField::Present(value))
1301-
}
1302-
}
1303-
13041244
#[cfg(not(taproot))]
13051245
impl_writeable_msg!(AcceptChannel, {
13061246
temporary_channel_id,
@@ -1317,8 +1257,8 @@ impl_writeable_msg!(AcceptChannel, {
13171257
delayed_payment_basepoint,
13181258
htlc_basepoint,
13191259
first_per_commitment_point,
1320-
shutdown_scriptpubkey
13211260
}, {
1261+
(0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
13221262
(1, channel_type, option),
13231263
});
13241264

@@ -1338,8 +1278,8 @@ impl_writeable_msg!(AcceptChannel, {
13381278
delayed_payment_basepoint,
13391279
htlc_basepoint,
13401280
first_per_commitment_point,
1341-
shutdown_scriptpubkey
13421281
}, {
1282+
(0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
13431283
(1, channel_type, option),
13441284
(4, next_local_nonce, option),
13451285
});
@@ -1477,8 +1417,8 @@ impl_writeable_msg!(OpenChannel, {
14771417
htlc_basepoint,
14781418
first_per_commitment_point,
14791419
channel_flags,
1480-
shutdown_scriptpubkey
14811420
}, {
1421+
(0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
14821422
(1, channel_type, option),
14831423
});
14841424

@@ -2103,7 +2043,7 @@ mod tests {
21032043
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
21042044
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
21052045
use crate::ln::msgs;
2106-
use crate::ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat};
2046+
use crate::ln::msgs::{FinalOnionHopData, OnionErrorPacket, OnionHopDataFormat};
21072047
use crate::routing::gossip::{NodeAlias, NodeId};
21082048
use crate::util::ser::{Writeable, Readable, Hostname};
21092049

@@ -2422,7 +2362,7 @@ mod tests {
24222362
htlc_basepoint: pubkey_5,
24232363
first_per_commitment_point: pubkey_6,
24242364
channel_flags: if random_bit { 1 << 5 } else { 0 },
2425-
shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent },
2365+
shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
24262366
channel_type: if incl_chan_type { Some(ChannelTypeFeatures::empty()) } else { None },
24272367
};
24282368
let encoded_value = open_channel.encode();
@@ -2478,7 +2418,7 @@ mod tests {
24782418
delayed_payment_basepoint: pubkey_4,
24792419
htlc_basepoint: pubkey_5,
24802420
first_per_commitment_point: pubkey_6,
2481-
shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent },
2421+
shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
24822422
channel_type: None,
24832423
#[cfg(taproot)]
24842424
next_local_nonce: None,

lightning/src/ln/shutdown_tests.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use regex;
3333
use core::default::Default;
3434

3535
use crate::ln::functional_test_utils::*;
36-
use crate::ln::msgs::OptionalField::Present;
3736

3837
#[test]
3938
fn pre_funding_lock_shutdown_test() {
@@ -517,7 +516,7 @@ fn test_unsupported_anysegwit_upfront_shutdown_script() {
517516
// Check script when handling an open_channel message
518517
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
519518
let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
520-
open_channel.shutdown_scriptpubkey = Present(anysegwit_shutdown_script.clone());
519+
open_channel.shutdown_scriptpubkey = Some(anysegwit_shutdown_script.clone());
521520
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
522521

523522
let events = nodes[1].node.get_and_clear_pending_msg_events();
@@ -542,7 +541,7 @@ fn test_unsupported_anysegwit_upfront_shutdown_script() {
542541
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
543542
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
544543
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
545-
accept_channel.shutdown_scriptpubkey = Present(anysegwit_shutdown_script.clone());
544+
accept_channel.shutdown_scriptpubkey = Some(anysegwit_shutdown_script.clone());
546545
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel);
547546

548547
let events = nodes[0].node.get_and_clear_pending_msg_events();
@@ -568,7 +567,7 @@ fn test_invalid_upfront_shutdown_script() {
568567

569568
// Use a segwit v0 script with an unsupported witness program
570569
let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
571-
open_channel.shutdown_scriptpubkey = Present(Builder::new().push_int(0)
570+
open_channel.shutdown_scriptpubkey = Some(Builder::new().push_int(0)
572571
.push_slice(&[0, 0])
573572
.into_script());
574573
nodes[0].node.handle_open_channel(&nodes[1].node.get_our_node_id(), &open_channel);

lightning/src/util/ser.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use bitcoin::secp256k1::constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, COMPACT_SI
2929
use bitcoin::secp256k1::ecdsa;
3030
use bitcoin::secp256k1::schnorr;
3131
use bitcoin::blockdata::constants::ChainHash;
32-
use bitcoin::blockdata::script::Script;
32+
use bitcoin::blockdata::script::{self, Script};
3333
use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
3434
use bitcoin::consensus;
3535
use bitcoin::consensus::Encodable;
@@ -657,6 +657,21 @@ impl<'a, T> From<&'a Vec<T>> for WithoutLength<&'a Vec<T>> {
657657
fn from(v: &'a Vec<T>) -> Self { Self(v) }
658658
}
659659

660+
impl Writeable for WithoutLength<&Script> {
661+
#[inline]
662+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
663+
writer.write_all(self.0.as_bytes())
664+
}
665+
}
666+
667+
impl Readable for WithoutLength<Script> {
668+
#[inline]
669+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
670+
let v: WithoutLength<Vec<u8>> = Readable::read(r)?;
671+
Ok(WithoutLength(script::Builder::from(v.0).into_script()))
672+
}
673+
}
674+
660675
#[derive(Debug)]
661676
pub(crate) struct Iterable<'a, I: Iterator<Item = &'a T> + Clone, T: 'a>(pub I);
662677

lightning/src/util/ser_macros.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ macro_rules! impl_writeable_msg {
554554
impl $crate::util::ser::Writeable for $st {
555555
fn write<W: $crate::util::ser::Writer>(&self, w: &mut W) -> Result<(), $crate::io::Error> {
556556
$( self.$field.write(w)?; )*
557-
$crate::encode_tlv_stream!(w, {$(($type, self.$tlvfield, $fieldty)),*});
557+
$crate::encode_tlv_stream!(w, {$(($type, self.$tlvfield.as_ref(), $fieldty)),*});
558558
Ok(())
559559
}
560560
}
@@ -726,6 +726,9 @@ macro_rules! _init_tlv_field_var {
726726
($field: ident, optional_vec) => {
727727
let mut $field = Some(Vec::new());
728728
};
729+
($field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
730+
$crate::_init_tlv_field_var!($field, option);
731+
};
729732
($field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {
730733
$crate::_init_tlv_field_var!($field, option);
731734
};

0 commit comments

Comments
 (0)