htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),
+ next_blinding_override: None,
},
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),
+ next_blinding_override: None,
},
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
///
/// [`BlindedHop::encrypted_payload`]: crate::blinded_path::BlindedHop::encrypted_payload
pub features: BlindedHopFeatures,
+ /// Set if this [`BlindedPaymentPath`] is concatenated to another, to indicate the
+ /// [`BlindedPaymentPath::blinding_point`] of the appended blinded path.
+ pub next_blinding_override: Option<PublicKey>,
}
/// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and
_init_and_read_tlv_stream!(r, {
(1, _padding, option),
(2, scid, option),
+ (8, next_blinding_override, option),
(10, payment_relay, option),
(12, payment_constraints, required),
(14, features, option),
short_channel_id,
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
payment_constraints: payment_constraints.0.unwrap(),
+ next_blinding_override,
features: features.unwrap_or_else(BlindedHopFeatures::empty),
}))
} else {
max_cltv_expiry: 0,
htlc_minimum_msat: 100,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value(),
max_cltv_expiry: 0,
htlc_minimum_msat: 1_000,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value(),
max_cltv_expiry: 0,
htlc_minimum_msat: 1,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
max_cltv_expiry: 0,
htlc_minimum_msat: 2_000,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
max_cltv_expiry: 0,
htlc_minimum_msat: 5_000,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
max_cltv_expiry: 0,
htlc_minimum_msat: 2_000,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: u64::max_value()
max_cltv_expiry: 0,
htlc_minimum_msat: 1,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: 5_000,
max_cltv_expiry: 0,
htlc_minimum_msat: 1,
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: 10_000
htlc_minimum_msat: intro_node_min_htlc_opt.take()
.unwrap_or_else(|| channel_upds[idx - 1].htlc_minimum_msat),
},
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
htlc_maximum_msat: intro_node_max_htlc_opt.take()
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,
+ /// Overrides the next hop's [`msgs::UpdateAddHTLC::blinding_point`]. Set if this HTLC is being
+ /// forwarded within a [`BlindedPaymentPath`] that was concatenated to another blinded path that
+ /// starts at the next hop.
+ pub next_blinding_override: Option<PublicKey>,
}
impl PendingHTLCRouting {
blinded_failure: blinded.map(|b| b.failure),
});
let next_blinding_point = blinded.and_then(|b| {
- let encrypted_tlvs_ss = self.node_signer.ecdh(
- Recipient::Node, &b.inbound_blinding_point, None
- ).unwrap().secret_bytes();
- onion_utils::next_hop_pubkey(
- &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss
- ).ok()
+ b.next_blinding_override.or_else(|| {
+ let encrypted_tlvs_ss = self.node_signer.ecdh(
+ Recipient::Node, &b.inbound_blinding_point, None
+ ).unwrap().secret_bytes();
+ onion_utils::next_hop_pubkey(
+ &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss
+ ).ok()
+ })
});
// Forward the HTLC over the most appropriate channel with the corresponding peer,
impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),
+ (3, next_blinding_override, option),
});
impl_writeable_tlv_based_enum!(PendingHTLCRouting,
payment_constraints: PaymentConstraints,
features: BlindedHopFeatures,
intro_node_blinding_point: Option<PublicKey>,
+ next_blinding_override: Option<PublicKey>,
},
BlindedReceive {
sender_intended_htlc_amt_msat: u64,
let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64);
match ChaChaPolyReadAdapter::read(&mut reader, rho)? {
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs {
- short_channel_id, payment_relay, payment_constraints, features
+ short_channel_id, payment_relay, payment_constraints, features, next_blinding_override
})} => {
if amt.is_some() || cltv_value.is_some() || total_msat.is_some() ||
keysend_preimage.is_some()
payment_constraints,
features,
intro_node_blinding_point,
+ next_blinding_override,
})
},
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
};
let (
- short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point
+ short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
+ next_blinding_override
) = match hop_data {
msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
- (short_channel_id, amt_to_forward, outgoing_cltv_value, None),
+ (short_channel_id, amt_to_forward, outgoing_cltv_value, None, None),
msgs::InboundOnionPayload::BlindedForward {
short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
+ next_blinding_override,
} => {
let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
err_data: vec![0; 32],
}
})?;
- (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point)
+ (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
+ next_blinding_override)
},
msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
return Err(InboundHTLCErr {
blinded: intro_node_blinding_point.or(msg.blinding_point)
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
+ next_blinding_override,
failure: intro_node_blinding_point
.map(|_| BlindedFailure::FromIntroductionNode)
.unwrap_or(BlindedFailure::FromBlindedNode),
short_channel_id,
payment_relay,
payment_constraints,
+ next_blinding_override: None,
features: BlindedHopFeatures::empty(),
},
node_id: details.counterparty.node_id,