@@ -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.
169184pub ( 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