Skip to content

Commit

Permalink
Replace OnionHopData with OutboundPayload for outbound onions
Browse files Browse the repository at this point in the history
Follows on from the previous commit, see its message
  • Loading branch information
valentinewallace committed Jul 13, 2023
1 parent 46794b9 commit eb3af58
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 92 deletions.
4 changes: 3 additions & 1 deletion lightning/src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8039,7 +8039,9 @@ fn test_onion_value_mpp_set_calculation() {
RecipientOnionFields::secret_only(our_payment_secret), height + 1, &None).unwrap();
// Edit amt_to_forward to simulate the sender having set
// the final amount and the routing node taking less fee
onion_payloads[1].amt_to_forward = 99_000;
if let msgs::OutboundPayload::Receive { ref mut amt_msat, .. } = onion_payloads[1] {
*amt_msat = 99_000;
} else { panic!() }
let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap();
payment_event.msgs[0].onion_routing_packet = new_onion_packet;
}
Expand Down
92 changes: 41 additions & 51 deletions lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,25 +1441,21 @@ mod fuzzy_internal_msgs {
},
}

pub(crate) enum OnionHopDataFormat {
NonFinalNode {
pub(crate) enum OutboundPayload {
Forward {
short_channel_id: u64,
amt_to_forward: u64,
outgoing_cltv_value: u32,
},
FinalNode {
Receive {
payment_data: Option<FinalOnionHopData>,
payment_metadata: Option<Vec<u8>>,
keysend_preimage: Option<PaymentPreimage>,
amt_msat: u64,
outgoing_cltv_value: u32,
},
}

pub struct OnionHopData {
pub(crate) format: OnionHopDataFormat,
/// The value, in msat, of the payment after this hop's fee is deducted.
/// Message serialization may panic if this value is more than 21 million Bitcoin.
pub(crate) amt_to_forward: u64,
pub(crate) outgoing_cltv_value: u32,
}

pub struct DecodedOnionErrorPacket {
pub(crate) hmac: [u8; 32],
pub(crate) failuremsg: Vec<u8>,
Expand Down Expand Up @@ -1966,20 +1962,22 @@ impl Readable for FinalOnionHopData {
}
}

impl Writeable for OnionHopData {
impl Writeable for OutboundPayload {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
match self.format {
OnionHopDataFormat::NonFinalNode { short_channel_id } => {
match self {
Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => {
_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
(2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(6, short_channel_id, required)
});
},
OnionHopDataFormat::FinalNode { ref payment_data, ref payment_metadata, ref keysend_preimage } => {
Self::Receive {
ref payment_data, ref payment_metadata, ref keysend_preimage, amt_msat, outgoing_cltv_value
} => {
_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
(2, HighZeroBytesDroppedBigSize(*amt_msat), required),
(4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(8, payment_data, option),
(16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option),
(5482373484, keysend_preimage, option)
Expand Down Expand Up @@ -2454,7 +2452,7 @@ mod tests {
use hex;
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, OnionHopDataFormat};
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket};
use crate::routing::gossip::{NodeAlias, NodeId};
use crate::util::ser::{Writeable, Readable, Hostname, TransactionU16LenLimited};

Expand Down Expand Up @@ -3537,14 +3535,12 @@ mod tests {

#[test]
fn encoding_nonfinal_onion_hop_data() {
let msg = msgs::OnionHopData {
format: OnionHopDataFormat::NonFinalNode {
short_channel_id: 0xdeadbeef1bad1dea,
},
let outbound_msg = msgs::OutboundPayload::Forward {
short_channel_id: 0xdeadbeef1bad1dea,
amt_to_forward: 0x0badf00d01020304,
outgoing_cltv_value: 0xffffffff,
};
let encoded_value = msg.encode();
let encoded_value = outbound_msg.encode();
let target_value = hex::decode("1a02080badf00d010203040404ffffffff0608deadbeef1bad1dea").unwrap();
assert_eq!(encoded_value, target_value);

Expand All @@ -3558,16 +3554,14 @@ mod tests {

#[test]
fn encoding_final_onion_hop_data() {
let msg = msgs::OnionHopData {
format: OnionHopDataFormat::FinalNode {
payment_data: None,
payment_metadata: None,
keysend_preimage: None,
},
amt_to_forward: 0x0badf00d01020304,
let outbound_msg = msgs::OutboundPayload::Receive {
payment_data: None,
payment_metadata: None,
keysend_preimage: None,
amt_msat: 0x0badf00d01020304,
outgoing_cltv_value: 0xffffffff,
};
let encoded_value = msg.encode();
let encoded_value = outbound_msg.encode();
let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap();
assert_eq!(encoded_value, target_value);

Expand All @@ -3581,19 +3575,17 @@ mod tests {
#[test]
fn encoding_final_onion_hop_data_with_secret() {
let expected_payment_secret = PaymentSecret([0x42u8; 32]);
let msg = msgs::OnionHopData {
format: OnionHopDataFormat::FinalNode {
payment_data: Some(FinalOnionHopData {
payment_secret: expected_payment_secret,
total_msat: 0x1badca1f
}),
payment_metadata: None,
keysend_preimage: None,
},
amt_to_forward: 0x0badf00d01020304,
let outbound_msg = msgs::OutboundPayload::Receive {
payment_data: Some(FinalOnionHopData {
payment_secret: expected_payment_secret,
total_msat: 0x1badca1f
}),
payment_metadata: None,
keysend_preimage: None,
amt_msat: 0x0badf00d01020304,
outgoing_cltv_value: 0xffffffff,
};
let encoded_value = msg.encode();
let encoded_value = outbound_msg.encode();
let target_value = hex::decode("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap();
assert_eq!(encoded_value, target_value);

Expand Down Expand Up @@ -3765,20 +3757,18 @@ mod tests {
// see above test, needs to be a separate method for use of the serialization macros.
fn encode_big_payload() -> Result<Vec<u8>, io::Error> {
use crate::util::ser::HighZeroBytesDroppedBigSize;
let payload = msgs::OnionHopData {
format: OnionHopDataFormat::NonFinalNode {
short_channel_id: 0xdeadbeef1bad1dea,
},
let payload = msgs::OutboundPayload::Forward {
short_channel_id: 0xdeadbeef1bad1dea,
amt_to_forward: 1000,
outgoing_cltv_value: 0xffffffff,
};
let mut encoded_payload = Vec::new();
let test_bytes = vec![42u8; 1000];
if let OnionHopDataFormat::NonFinalNode { short_channel_id } = payload.format {
if let msgs::OutboundPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } = payload {
_encode_varint_length_prefixed_tlv!(&mut encoded_payload, {
(1, test_bytes, required_vec),
(2, HighZeroBytesDroppedBigSize(payload.amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(payload.outgoing_cltv_value), required),
(2, HighZeroBytesDroppedBigSize(amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(outgoing_cltv_value), required),
(6, short_channel_id, required)
});
}
Expand Down
10 changes: 5 additions & 5 deletions lightning/src/ln/onion_route_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ struct BogusOnionHopData {
data: Vec<u8>
}
impl BogusOnionHopData {
fn new(orig: msgs::OnionHopData) -> Self {
fn new(orig: msgs::OutboundPayload) -> Self {
Self { data: orig.encode() }
}
}
Expand Down Expand Up @@ -875,15 +875,15 @@ fn test_always_create_tlv_format_onion_payloads() {
let (onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();

match onion_payloads[0].format {
msgs::OnionHopDataFormat::NonFinalNode {..} => {},
match onion_payloads[0] {
msgs::OutboundPayload::Forward {..} => {},
_ => { panic!(
"Should have generated a `msgs::OnionHopDataFormat::NonFinalNode` payload for `hops[0]`,
despite that the features signals no support for variable length onions"
)}
}
match onion_payloads[1].format {
msgs::OnionHopDataFormat::FinalNode {..} => {},
match onion_payloads[1] {
msgs::OutboundPayload::Receive {..} => {},
_ => {panic!(
"Should have generated a `msgs::OnionHopDataFormat::FinalNode` payload for `hops[1]`,
despite that the features signals no support for variable length onions"
Expand Down
67 changes: 32 additions & 35 deletions lightning/src/ln/onion_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,37 +149,37 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T
}

/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
pub(super) fn build_onion_payloads(path: &Path, total_msat: u64, mut recipient_onion: RecipientOnionFields, starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
pub(super) fn build_onion_payloads(path: &Path, total_msat: u64, mut recipient_onion: RecipientOnionFields, starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>) -> Result<(Vec<msgs::OutboundPayload>, u64, u32), APIError> {
let mut cur_value_msat = 0u64;
let mut cur_cltv = starting_htlc_offset;
let mut last_short_channel_id = 0;
let mut res: Vec<msgs::OnionHopData> = Vec::with_capacity(path.hops.len());
let mut res: Vec<msgs::OutboundPayload> = Vec::with_capacity(path.hops.len());

for (idx, hop) in path.hops.iter().rev().enumerate() {
// First hop gets special values so that it can check, on receipt, that everything is
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
// the intended recipient).
let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat };
let cltv = if cur_cltv == starting_htlc_offset { hop.cltv_expiry_delta + starting_htlc_offset } else { cur_cltv };
res.insert(0, msgs::OnionHopData {
format: if idx == 0 {
msgs::OnionHopDataFormat::FinalNode {
payment_data: if let Some(secret) = recipient_onion.payment_secret.take() {
Some(msgs::FinalOnionHopData {
payment_secret: secret,
total_msat,
})
} else { None },
payment_metadata: recipient_onion.payment_metadata.take(),
keysend_preimage: *keysend_preimage,
}
} else {
msgs::OnionHopDataFormat::NonFinalNode {
short_channel_id: last_short_channel_id,
}
},
amt_to_forward: value_msat,
outgoing_cltv_value: cltv,
res.insert(0, if idx == 0 {
msgs::OutboundPayload::Receive {
payment_data: if let Some(secret) = recipient_onion.payment_secret.take() {
Some(msgs::FinalOnionHopData {
payment_secret: secret,
total_msat,
})
} else { None },
payment_metadata: recipient_onion.payment_metadata.take(),
keysend_preimage: *keysend_preimage,
amt_msat: value_msat,
outgoing_cltv_value: cltv,
}
} else {
msgs::OutboundPayload::Forward {
short_channel_id: last_short_channel_id,
amt_to_forward: value_msat,
outgoing_cltv_value: cltv,
}
});
cur_value_msat += hop.fee_msat;
if cur_value_msat >= 21000000 * 100000000 * 1000 {
Expand Down Expand Up @@ -208,7 +208,10 @@ fn shift_slice_right(arr: &mut [u8], amt: usize) {
}
}

pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> Result<msgs::OnionPacket, ()> {
pub(super) fn construct_onion_packet(
payloads: Vec<msgs::OutboundPayload>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32],
associated_data: &PaymentHash
) -> Result<msgs::OnionPacket, ()> {
let mut packet_data = [0; ONION_DATA_LEN];

let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
Expand Down Expand Up @@ -988,10 +991,8 @@ mod tests {
// with raw hex instead of our in-memory enums, as the payloads contains custom types, and
// we have no way of representing that with our enums.
let payloads = vec!(
RawOnionHopData::new(msgs::OnionHopData {
format: msgs::OnionHopDataFormat::NonFinalNode {
short_channel_id: 1,
},
RawOnionHopData::new(msgs::OutboundPayload::Forward {
short_channel_id: 1,
amt_to_forward: 15000,
outgoing_cltv_value: 1500,
}),
Expand All @@ -1013,17 +1014,13 @@ mod tests {
RawOnionHopData {
data: hex::decode("52020236b00402057806080000000000000002fd02013c0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f").unwrap(),
},
RawOnionHopData::new(msgs::OnionHopData {
format: msgs::OnionHopDataFormat::NonFinalNode {
short_channel_id: 3,
},
RawOnionHopData::new(msgs::OutboundPayload::Forward {
short_channel_id: 3,
amt_to_forward: 12500,
outgoing_cltv_value: 1250,
}),
RawOnionHopData::new(msgs::OnionHopData {
format: msgs::OnionHopDataFormat::NonFinalNode {
short_channel_id: 4,
},
RawOnionHopData::new(msgs::OutboundPayload::Forward {
short_channel_id: 4,
amt_to_forward: 10000,
outgoing_cltv_value: 1000,
}),
Expand Down Expand Up @@ -1101,7 +1098,7 @@ mod tests {
data: Vec<u8>
}
impl RawOnionHopData {
fn new(orig: msgs::OnionHopData) -> Self {
fn new(orig: msgs::OutboundPayload) -> Self {
Self { data: orig.encode() }
}
}
Expand Down

0 comments on commit eb3af58

Please sign in to comment.