Skip to content

Commit 63f26af

Browse files
zoedbergafilinidanielabrozzoni
committed
Add support for swaps
- Also fix a bug where we wouldn't reject payments with non-matching rgb amounts Co-Authored-By: Alekos Filini <alekos.filini@gmail.com> Co-Authored-By: Daniela Brozzoni <danielabrozzoni@protonmail.com>
1 parent 153f521 commit 63f26af

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3157,15 +3157,15 @@ where
31573157
return_err!(err_msg, err_code, &[0; 0]);
31583158
},
31593159
};
3160-
let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt) = match next_hop {
3160+
let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt, outgoing_amount_rgb) = match next_hop {
31613161
onion_utils::Hop::Forward {
31623162
next_hop_data: msgs::InboundOnionPayload::Forward {
3163-
short_channel_id, amt_to_forward, outgoing_cltv_value, ..
3163+
short_channel_id, amt_to_forward, outgoing_cltv_value, rgb_amount_to_forward, ..
31643164
}, ..
31653165
} => {
31663166
let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
31673167
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
3168-
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
3168+
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk), rgb_amount_to_forward)
31693169
},
31703170
// We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
31713171
// inbound channel's state.
@@ -3187,7 +3187,8 @@ where
31873187
// phantom or an intercept.
31883188
if (self.default_configuration.accept_intercept_htlcs &&
31893189
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)) ||
3190-
fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)
3190+
fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash) ||
3191+
fake_scid::is_valid_swap(outgoing_scid)
31913192
{
31923193
None
31933194
} else {
@@ -3249,6 +3250,20 @@ where
32493250
if let Err((err, code)) = chan.htlc_satisfies_config(&msg, outgoing_amt_msat, outgoing_cltv_value) {
32503251
break Some((err, code, chan_update_opt));
32513252
}
3253+
match (msg.amount_rgb, outgoing_amount_rgb) {
3254+
(Some(_), None) | (None, Some(_)) => {
3255+
// using amount_below_minimum error because there is no better error available
3256+
break Some(("Refusing to forward a non-authorized swap.", 0x1000 | 11, chan_update_opt));
3257+
},
3258+
(None, None) => {},
3259+
(Some(x), Some(y)) if x == y => {
3260+
log_trace!(self.logger, "Forwarding RGB payment of value: {}", x);
3261+
},
3262+
_ => {
3263+
// using amount_below_minimum error because there is no better error available
3264+
break Some(("Refusing to forward a payment with non-matching RGB amount", 0x1000 | 11, chan_update_opt)); // amount_below_minimum
3265+
}
3266+
}
32523267
chan_update_opt
32533268
} else {
32543269
if (msg.cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
@@ -3459,7 +3474,7 @@ where
34593474
let rgb_payment_info_hash_path = self.ldk_data_dir.join(htlc_payment_hash);
34603475
let path = if rgb_payment_info_hash_path.exists() {
34613476
let rgb_payment_info = parse_rgb_payment_info(&rgb_payment_info_hash_path);
3462-
if !rgb_payment_info.override_route_amount {
3477+
if rgb_payment_info.override_route_amount {
34633478
let mut path = path.clone();
34643479
for hop in &mut path.hops {
34653480
hop.rgb_amount = Some(rgb_payment_info.amount);

lightning/src/ln/onion_utils.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,26 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T
166166
}
167167

168168
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
169+
// NOTE: This function is slightly different from the rust-lightning one, as we had to modify
170+
// it in order to support RGB swaps. More details:
171+
// We now split up the bitcoin amount into a fee part and a payment part: in non-RGB nodes the
172+
// bitcoin amount is always monotonically increasing when constructing the route in reverse
173+
// (notice the .rev() in the function): the receiver gets x, the previous hop gets
174+
// `x + <fee to fwd to receiver>`, the previous one gets `x + <fee to fwd to next> +
175+
// <fee to fwd to receiver>` and so on. So the original function could get away with only
176+
// having one accumulator cur_value_msat that would always increase.
177+
// Now with RGB, and specifically RGB swaps, we have scenarios where this assumption doesn't hold
178+
// true: for example, when we send a payment that is initially RGB and then bitcoin (i.e. the
179+
// user is buying an asset) this doesn't work. At some point in the route the bitcoin amount
180+
// will suddenly need to decrease, because one node in the path (the user's node) is
181+
// sending more bitcoin than it's actually receiving.
182+
// So the new logic splits fees and payment_amount. We only accumulate fees, and for every node in the "bitcoin side"
183+
// of the path we also set the payment_amount, while for the other nodes it will be 0.
169184
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::OutboundOnionPayload>, u64, u32, Option<u64>), APIError> {
170-
let mut cur_value_msat = 0u64;
171185
// The rgb_amount at the last hop
172186
let mut last_amount_rgb = None;
187+
let mut last_msat_amount = 0;
188+
let mut cur_accumulated_fees = 0;
173189
let mut cur_cltv = starting_htlc_offset;
174190
let mut last_short_channel_id = 0;
175191
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
@@ -180,8 +196,10 @@ pub(super) fn build_onion_payloads(path: &Path, total_msat: u64, mut recipient_o
180196
// First hop gets special values so that it can check, on receipt, that everything is
181197
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
182198
// the intended recipient).
183-
let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat };
184-
let value_rgb = hop.rgb_amount;
199+
let (value_msat, value_rgb) = if last_msat_amount == 0 { (hop.fee_msat, hop.rgb_amount) } else {
200+
cur_accumulated_fees += hop.fee_msat;
201+
(last_msat_amount, last_amount_rgb)
202+
};
185203
let cltv = if cur_cltv == starting_htlc_offset { hop.cltv_expiry_delta + starting_htlc_offset } else { cur_cltv };
186204
if idx == 0 {
187205
if let Some(BlindedTail {
@@ -190,7 +208,6 @@ pub(super) fn build_onion_payloads(path: &Path, total_msat: u64, mut recipient_o
190208
let mut blinding_point = Some(*blinding_point);
191209
for (i, blinded_hop) in hops.iter().enumerate() {
192210
if i == hops.len() - 1 {
193-
cur_value_msat += final_value_msat;
194211
cur_cltv += excess_final_cltv_expiry_delta;
195212
res.push(msgs::OutboundOnionPayload::BlindedReceive {
196213
amt_msat: *final_value_msat,
@@ -231,18 +248,19 @@ pub(super) fn build_onion_payloads(path: &Path, total_msat: u64, mut recipient_o
231248
rgb_amount_to_forward: value_rgb,
232249
});
233250
}
234-
cur_value_msat += hop.fee_msat;
235-
if cur_value_msat >= 21000000 * 100000000 * 1000 {
251+
last_amount_rgb = hop.rgb_amount;
252+
last_msat_amount = hop.payment_amount + cur_accumulated_fees;
253+
254+
if last_msat_amount >= 21000000 * 100000000 * 1000 {
236255
return Err(APIError::InvalidRoute{err: "Channel fees overflowed?".to_owned()});
237256
}
238257
cur_cltv += hop.cltv_expiry_delta as u32;
239258
if cur_cltv >= 500000000 {
240259
return Err(APIError::InvalidRoute{err: "Channel CLTV overflowed?".to_owned()});
241260
}
242261
last_short_channel_id = hop.short_channel_id;
243-
last_amount_rgb = hop.rgb_amount;
244262
}
245-
Ok((res, cur_value_msat, cur_cltv, last_amount_rgb))
263+
Ok((res, last_msat_amount, cur_cltv, last_amount_rgb))
246264
}
247265

248266
/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now

0 commit comments

Comments
 (0)