Skip to content

Commit d3981e1

Browse files
committed
Create structs for InboundOnionPayload variants
In an upcoming commit, we will eliminate various invalid state combinations between `Hop` and `InboundOnionPayload` enums. To do so, rather than nesting one within the other, we will instead have them both referring to the same structs, with variant-dependent supplemental data. This requires pulling each variant's data into its own type.
1 parent b05402a commit d3981e1

File tree

5 files changed

+91
-81
lines changed

5 files changed

+91
-81
lines changed

lightning/src/ln/blinded_payment_tests.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1561,9 +1561,9 @@ fn route_blinding_spec_test_vector() {
15611561
_ => panic!("Unexpected error")
15621562
};
15631563
let (carol_packet_bytes, carol_hmac) = if let onion_utils::Hop::Forward {
1564-
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
1564+
next_hop_data: msgs::InboundOnionPayload::BlindedForward(msgs::InboundOnionBlindedForwardPayload {
15651565
short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override
1566-
}, next_hop_hmac, new_packet_bytes
1566+
}), next_hop_hmac, new_packet_bytes
15671567
} = bob_peeled_onion {
15681568
assert_eq!(short_channel_id, 1729);
15691569
assert!(next_blinding_override.is_none());
@@ -1595,9 +1595,9 @@ fn route_blinding_spec_test_vector() {
15951595
_ => panic!("Unexpected error")
15961596
};
15971597
let (dave_packet_bytes, dave_hmac) = if let onion_utils::Hop::Forward {
1598-
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
1598+
next_hop_data: msgs::InboundOnionPayload::BlindedForward(msgs::InboundOnionBlindedForwardPayload {
15991599
short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override
1600-
}, next_hop_hmac, new_packet_bytes
1600+
}), next_hop_hmac, new_packet_bytes
16011601
} = carol_peeled_onion {
16021602
assert_eq!(short_channel_id, 1105);
16031603
assert_eq!(next_blinding_override, Some(pubkey_from_hex("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f")));
@@ -1629,9 +1629,9 @@ fn route_blinding_spec_test_vector() {
16291629
_ => panic!("Unexpected error")
16301630
};
16311631
let (eve_packet_bytes, eve_hmac) = if let onion_utils::Hop::Forward {
1632-
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
1632+
next_hop_data: msgs::InboundOnionPayload::BlindedForward(msgs::InboundOnionBlindedForwardPayload {
16331633
short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override
1634-
}, next_hop_hmac, new_packet_bytes
1634+
}), next_hop_hmac, new_packet_bytes
16351635
} = dave_peeled_onion {
16361636
assert_eq!(short_channel_id, 561);
16371637
assert!(next_blinding_override.is_none());

lightning/src/ln/channelmanager.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -15570,16 +15570,17 @@ mod tests {
1557015570
let node = create_network(1, &node_cfg, &node_chanmgr);
1557115571
let sender_intended_amt_msat = 100;
1557215572
let extra_fee_msat = 10;
15573-
let hop_data = msgs::InboundOnionPayload::Receive {
15573+
let hop_data = msgs::InboundOnionPayload::Receive(msgs::InboundOnionReceivePayload {
1557415574
sender_intended_htlc_amt_msat: 100,
1557515575
cltv_expiry_height: 42,
1557615576
payment_metadata: None,
1557715577
keysend_preimage: None,
1557815578
payment_data: Some(msgs::FinalOnionHopData {
15579-
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
15579+
payment_secret: PaymentSecret([0; 32]),
15580+
total_msat: sender_intended_amt_msat,
1558015581
}),
1558115582
custom_tlvs: Vec::new(),
15582-
};
15583+
});
1558315584
// Check that if the amount we received + the penultimate hop extra fee is less than the sender
1558415585
// intended amount, we fail the payment.
1558515586
let current_height: u32 = node[0].node.best_block.read().unwrap().height;
@@ -15592,16 +15593,17 @@ mod tests {
1559215593
} else { panic!(); }
1559315594

1559415595
// If amt_received + extra_fee is equal to the sender intended amount, we're fine.
15595-
let hop_data = msgs::InboundOnionPayload::Receive { // This is the same payload as above, InboundOnionPayload doesn't implement Clone
15596+
let hop_data = msgs::InboundOnionPayload::Receive(msgs::InboundOnionReceivePayload { // This is the same payload as above, InboundOnionPayload doesn't implement Clone
1559615597
sender_intended_htlc_amt_msat: 100,
1559715598
cltv_expiry_height: 42,
1559815599
payment_metadata: None,
1559915600
keysend_preimage: None,
1560015601
payment_data: Some(msgs::FinalOnionHopData {
15601-
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
15602+
payment_secret: PaymentSecret([0; 32]),
15603+
total_msat: sender_intended_amt_msat,
1560215604
}),
1560315605
custom_tlvs: Vec::new(),
15604-
};
15606+
});
1560515607
let current_height: u32 = node[0].node.best_block.read().unwrap().height;
1560615608
assert!(create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
1560715609
sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat),
@@ -15616,16 +15618,17 @@ mod tests {
1561615618
let node = create_network(1, &node_cfg, &node_chanmgr);
1561715619

1561815620
let current_height: u32 = node[0].node.best_block.read().unwrap().height;
15619-
let result = create_recv_pending_htlc_info(msgs::InboundOnionPayload::Receive {
15621+
let result = create_recv_pending_htlc_info(msgs::InboundOnionPayload::Receive(msgs::InboundOnionReceivePayload {
1562015622
sender_intended_htlc_amt_msat: 100,
1562115623
cltv_expiry_height: 22,
1562215624
payment_metadata: None,
1562315625
keysend_preimage: None,
1562415626
payment_data: Some(msgs::FinalOnionHopData {
15625-
payment_secret: PaymentSecret([0; 32]), total_msat: 100,
15627+
payment_secret: PaymentSecret([0; 32]),
15628+
total_msat: 100,
1562615629
}),
1562715630
custom_tlvs: Vec::new(),
15628-
}, [0; 32], PaymentHash([0; 32]), 100, 23, None, true, None, current_height);
15631+
}), [0; 32], PaymentHash([0; 32]), 100, 23, None, true, None, current_height);
1562915632

1563015633
// Should not return an error as this condition:
1563115634
// https://github.com/lightning/bolts/blob/4dcc377209509b13cf89a4b91fde7d478f5b46d8/04-onion-routing.md?plain=1#L334

lightning/src/ln/msgs.rs

+58-52
Original file line numberDiff line numberDiff line change
@@ -1768,41 +1768,47 @@ mod fuzzy_internal_msgs {
17681768
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
17691769
// them from untrusted input):
17701770

1771+
pub struct InboundOnionForwardPayload {
1772+
pub short_channel_id: u64,
1773+
/// The value, in msat, of the payment after this hop's fee is deducted.
1774+
pub amt_to_forward: u64,
1775+
pub outgoing_cltv_value: u32,
1776+
}
1777+
1778+
pub struct InboundOnionReceivePayload {
1779+
pub payment_data: Option<FinalOnionHopData>,
1780+
pub payment_metadata: Option<Vec<u8>>,
1781+
pub keysend_preimage: Option<PaymentPreimage>,
1782+
pub custom_tlvs: Vec<(u64, Vec<u8>)>,
1783+
pub sender_intended_htlc_amt_msat: u64,
1784+
pub cltv_expiry_height: u32,
1785+
}
1786+
pub struct InboundOnionBlindedForwardPayload {
1787+
pub short_channel_id: u64,
1788+
pub payment_relay: PaymentRelay,
1789+
pub payment_constraints: PaymentConstraints,
1790+
pub features: BlindedHopFeatures,
1791+
pub intro_node_blinding_point: Option<PublicKey>,
1792+
pub next_blinding_override: Option<PublicKey>,
1793+
}
1794+
pub struct InboundOnionBlindedReceivePayload {
1795+
pub sender_intended_htlc_amt_msat: u64,
1796+
pub total_msat: u64,
1797+
pub cltv_expiry_height: u32,
1798+
pub payment_secret: PaymentSecret,
1799+
pub payment_constraints: PaymentConstraints,
1800+
pub payment_context: PaymentContext,
1801+
pub intro_node_blinding_point: Option<PublicKey>,
1802+
pub keysend_preimage: Option<PaymentPreimage>,
1803+
pub invoice_request: Option<InvoiceRequest>,
1804+
pub custom_tlvs: Vec<(u64, Vec<u8>)>,
1805+
}
1806+
17711807
pub enum InboundOnionPayload {
1772-
Forward {
1773-
short_channel_id: u64,
1774-
/// The value, in msat, of the payment after this hop's fee is deducted.
1775-
amt_to_forward: u64,
1776-
outgoing_cltv_value: u32,
1777-
},
1778-
Receive {
1779-
payment_data: Option<FinalOnionHopData>,
1780-
payment_metadata: Option<Vec<u8>>,
1781-
keysend_preimage: Option<PaymentPreimage>,
1782-
custom_tlvs: Vec<(u64, Vec<u8>)>,
1783-
sender_intended_htlc_amt_msat: u64,
1784-
cltv_expiry_height: u32,
1785-
},
1786-
BlindedForward {
1787-
short_channel_id: u64,
1788-
payment_relay: PaymentRelay,
1789-
payment_constraints: PaymentConstraints,
1790-
features: BlindedHopFeatures,
1791-
intro_node_blinding_point: Option<PublicKey>,
1792-
next_blinding_override: Option<PublicKey>,
1793-
},
1794-
BlindedReceive {
1795-
sender_intended_htlc_amt_msat: u64,
1796-
total_msat: u64,
1797-
cltv_expiry_height: u32,
1798-
payment_secret: PaymentSecret,
1799-
payment_constraints: PaymentConstraints,
1800-
payment_context: PaymentContext,
1801-
intro_node_blinding_point: Option<PublicKey>,
1802-
keysend_preimage: Option<PaymentPreimage>,
1803-
invoice_request: Option<InvoiceRequest>,
1804-
custom_tlvs: Vec<(u64, Vec<u8>)>,
1805-
}
1808+
Forward(InboundOnionForwardPayload),
1809+
Receive(InboundOnionReceivePayload),
1810+
BlindedForward(InboundOnionBlindedForwardPayload),
1811+
BlindedReceive(InboundOnionBlindedReceivePayload),
18061812
}
18071813

18081814
pub(crate) enum OutboundOnionPayload<'a> {
@@ -2907,14 +2913,14 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
29072913
{
29082914
return Err(DecodeError::InvalidValue)
29092915
}
2910-
Ok(Self::BlindedForward {
2916+
Ok(Self::BlindedForward(InboundOnionBlindedForwardPayload {
29112917
short_channel_id,
29122918
payment_relay,
29132919
payment_constraints,
29142920
features,
29152921
intro_node_blinding_point,
29162922
next_blinding_override,
2917-
})
2923+
}))
29182924
},
29192925
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(receive_tlvs) } => {
29202926
let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs;
@@ -2927,7 +2933,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
29272933
payment_secret, payment_constraints, payment_context,
29282934
} = tlvs;
29292935
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
2930-
Ok(Self::BlindedReceive {
2936+
Ok(Self::BlindedReceive(InboundOnionBlindedReceivePayload {
29312937
sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
29322938
total_msat: total_msat.ok_or(DecodeError::InvalidValue)?,
29332939
cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
@@ -2938,18 +2944,18 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
29382944
keysend_preimage,
29392945
invoice_request,
29402946
custom_tlvs,
2941-
})
2947+
}))
29422948
},
29432949
}
29442950
} else if let Some(short_channel_id) = short_id {
29452951
if payment_data.is_some() || payment_metadata.is_some() || encrypted_tlvs_opt.is_some() ||
29462952
total_msat.is_some() || invoice_request.is_some()
29472953
{ return Err(DecodeError::InvalidValue) }
2948-
Ok(Self::Forward {
2954+
Ok(Self::Forward(InboundOnionForwardPayload {
29492955
short_channel_id,
29502956
amt_to_forward: amt.ok_or(DecodeError::InvalidValue)?,
29512957
outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
2952-
})
2958+
}))
29532959
} else {
29542960
if encrypted_tlvs_opt.is_some() || total_msat.is_some() || invoice_request.is_some() {
29552961
return Err(DecodeError::InvalidValue)
@@ -2959,14 +2965,14 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
29592965
return Err(DecodeError::InvalidValue);
29602966
}
29612967
}
2962-
Ok(Self::Receive {
2968+
Ok(Self::Receive(InboundOnionReceivePayload {
29632969
payment_data,
29642970
payment_metadata: payment_metadata.map(|w| w.0),
29652971
keysend_preimage,
29662972
sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
29672973
cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
29682974
custom_tlvs,
2969-
})
2975+
}))
29702976
}
29712977
}
29722978
}
@@ -3387,7 +3393,7 @@ mod tests {
33873393
use crate::ln::types::ChannelId;
33883394
use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret};
33893395
use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
3390-
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields, OutboundTrampolinePayload, TrampolineOnionPacket};
3396+
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields, OutboundTrampolinePayload, TrampolineOnionPacket, InboundOnionForwardPayload, InboundOnionReceivePayload};
33913397
use crate::ln::msgs::SocketAddress;
33923398
use crate::routing::gossip::{NodeAlias, NodeId};
33933399
use crate::util::ser::{BigSize, FixedLengthReader, Hostname, LengthReadable, Readable, ReadableArgs, TransactionU16LenLimited, Writeable};
@@ -4559,9 +4565,9 @@ mod tests {
45594565

45604566
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
45614567
let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &node_signer)).unwrap();
4562-
if let msgs::InboundOnionPayload::Forward {
4568+
if let msgs::InboundOnionPayload::Forward(InboundOnionForwardPayload {
45634569
short_channel_id, amt_to_forward, outgoing_cltv_value
4564-
} = inbound_msg {
4570+
}) = inbound_msg {
45654571
assert_eq!(short_channel_id, 0xdeadbeef1bad1dea);
45664572
assert_eq!(amt_to_forward, 0x0badf00d01020304);
45674573
assert_eq!(outgoing_cltv_value, 0xffffffff);
@@ -4584,9 +4590,9 @@ mod tests {
45844590

45854591
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
45864592
let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &node_signer)).unwrap();
4587-
if let msgs::InboundOnionPayload::Receive {
4593+
if let msgs::InboundOnionPayload::Receive(InboundOnionReceivePayload {
45884594
payment_data: None, sender_intended_htlc_amt_msat, cltv_expiry_height, ..
4589-
} = inbound_msg {
4595+
}) = inbound_msg {
45904596
assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304);
45914597
assert_eq!(cltv_expiry_height, 0xffffffff);
45924598
} else { panic!(); }
@@ -4612,7 +4618,7 @@ mod tests {
46124618

46134619
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
46144620
let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &node_signer)).unwrap();
4615-
if let msgs::InboundOnionPayload::Receive {
4621+
if let msgs::InboundOnionPayload::Receive(InboundOnionReceivePayload {
46164622
payment_data: Some(FinalOnionHopData {
46174623
payment_secret,
46184624
total_msat: 0x1badca1f
@@ -4621,7 +4627,7 @@ mod tests {
46214627
payment_metadata: None,
46224628
keysend_preimage: None,
46234629
custom_tlvs,
4624-
} = inbound_msg {
4630+
}) = inbound_msg {
46254631
assert_eq!(payment_secret, expected_payment_secret);
46264632
assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304);
46274633
assert_eq!(cltv_expiry_height, 0xffffffff);
@@ -4658,7 +4664,7 @@ mod tests {
46584664
let encoded_value = msg.encode();
46594665
let inbound_msg = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), (None, &node_signer)).unwrap();
46604666
match inbound_msg {
4661-
msgs::InboundOnionPayload::Receive { custom_tlvs, .. } => assert!(custom_tlvs.is_empty()),
4667+
msgs::InboundOnionPayload::Receive(InboundOnionReceivePayload { custom_tlvs, .. }) => assert!(custom_tlvs.is_empty()),
46624668
_ => panic!(),
46634669
}
46644670
}
@@ -4682,15 +4688,15 @@ mod tests {
46824688
assert_eq!(encoded_value, target_value);
46834689
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
46844690
let inbound_msg: msgs::InboundOnionPayload = ReadableArgs::read(&mut Cursor::new(&target_value[..]), (None, &node_signer)).unwrap();
4685-
if let msgs::InboundOnionPayload::Receive {
4691+
if let msgs::InboundOnionPayload::Receive(InboundOnionReceivePayload {
46864692
payment_data: None,
46874693
payment_metadata: None,
46884694
keysend_preimage: None,
46894695
custom_tlvs,
46904696
sender_intended_htlc_amt_msat,
46914697
cltv_expiry_height: outgoing_cltv_value,
46924698
..
4693-
} = inbound_msg {
4699+
}) = inbound_msg {
46944700
assert_eq!(custom_tlvs, expected_custom_tlvs);
46954701
assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304);
46964702
assert_eq!(outgoing_cltv_value, 0xffffffff);

lightning/src/ln/onion_payment.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ pub(super) fn create_fwd_pending_htlc_info(
7878
short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
7979
next_blinding_override
8080
) = match hop_data {
81-
msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
81+
msgs::InboundOnionPayload::Forward(msgs::InboundOnionForwardPayload { short_channel_id, amt_to_forward, outgoing_cltv_value }) =>
8282
(short_channel_id, amt_to_forward, outgoing_cltv_value, None, None),
83-
msgs::InboundOnionPayload::BlindedForward {
83+
msgs::InboundOnionPayload::BlindedForward(msgs::InboundOnionBlindedForwardPayload {
8484
short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
8585
next_blinding_override,
86-
} => {
86+
}) => {
8787
let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
8888
msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
8989
).map_err(|()| {
@@ -139,17 +139,17 @@ pub(super) fn create_recv_pending_htlc_info(
139139
payment_metadata, payment_context, requires_blinded_error, has_recipient_created_payment_secret,
140140
invoice_request
141141
) = match hop_data {
142-
msgs::InboundOnionPayload::Receive {
142+
msgs::InboundOnionPayload::Receive(msgs::InboundOnionReceivePayload {
143143
payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
144144
cltv_expiry_height, payment_metadata, ..
145-
} =>
145+
}) =>
146146
(payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
147147
cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None),
148-
msgs::InboundOnionPayload::BlindedReceive {
148+
msgs::InboundOnionPayload::BlindedReceive(msgs::InboundOnionBlindedReceivePayload {
149149
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
150150
intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
151151
custom_tlvs, invoice_request
152-
} => {
152+
}) => {
153153
check_blinded_payment_constraints(
154154
sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
155155
)
@@ -425,9 +425,9 @@ where
425425

426426
let next_packet_details = match next_hop {
427427
onion_utils::Hop::Forward {
428-
next_hop_data: msgs::InboundOnionPayload::Forward {
428+
next_hop_data: msgs::InboundOnionPayload::Forward(msgs::InboundOnionForwardPayload {
429429
short_channel_id, amt_to_forward, outgoing_cltv_value
430-
}, ..
430+
}), ..
431431
} => {
432432
let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
433433
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
@@ -437,9 +437,9 @@ where
437437
}
438438
},
439439
onion_utils::Hop::Forward {
440-
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
440+
next_hop_data: msgs::InboundOnionPayload::BlindedForward (msgs::InboundOnionBlindedForwardPayload{
441441
short_channel_id, ref payment_relay, ref payment_constraints, ref features, ..
442-
}, ..
442+
}), ..
443443
} => {
444444
let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
445445
msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features

lightning/src/ln/onion_utils.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1434,9 +1434,10 @@ impl Hop {
14341434
match self {
14351435
Self::Forward {
14361436
next_hop_data:
1437-
msgs::InboundOnionPayload::BlindedForward {
1438-
intro_node_blinding_point: Some(_), ..
1439-
},
1437+
msgs::InboundOnionPayload::BlindedForward(msgs::InboundOnionBlindedForwardPayload {
1438+
intro_node_blinding_point: Some(_),
1439+
..
1440+
}),
14401441
..
14411442
} => true,
14421443
_ => false,

0 commit comments

Comments
 (0)