Merge pull request #3342 from shaavan/i3262

Introduce RouteParametersConfig
This commit is contained in:
Matt Corallo 2025-02-25 15:12:49 +00:00 committed by GitHub
commit ece4ab7cb7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 323 additions and 98 deletions

View file

@ -170,6 +170,7 @@ mod test {
use lightning::onion_message::messenger::{ use lightning::onion_message::messenger::{
AOnionMessenger, Destination, MessageRouter, OnionMessagePath, OnionMessenger, AOnionMessenger, Destination, MessageRouter, OnionMessagePath, OnionMessenger,
}; };
use lightning::routing::router::RouteParametersConfig;
use lightning::sign::{KeysManager, NodeSigner, Recipient}; use lightning::sign::{KeysManager, NodeSigner, Recipient};
use lightning::types::features::InitFeatures; use lightning::types::features::InitFeatures;
use lightning::types::payment::PaymentHash; use lightning::types::payment::PaymentHash;
@ -405,7 +406,14 @@ mod test {
let amt = 42_000; let amt = 42_000;
nodes[0] nodes[0]
.node .node
.pay_for_offer_from_human_readable_name(name, amt, payment_id, retry, None, resolvers) .pay_for_offer_from_human_readable_name(
name,
amt,
payment_id,
retry,
RouteParametersConfig::default(),
resolvers,
)
.unwrap(); .unwrap();
let query = nodes[0].onion_messenger.next_onion_message_for_peer(resolver_id).unwrap(); let query = nodes[0].onion_messenger.next_onion_message_for_peer(resolver_id).unwrap();

View file

@ -33,7 +33,7 @@ use crate::onion_message::messenger::{Destination, MessageRouter, MessageSendIns
use crate::onion_message::offers::OffersMessage; use crate::onion_message::offers::OffersMessage;
use crate::onion_message::packet::ParsedOnionMessageContents; use crate::onion_message::packet::ParsedOnionMessageContents;
use crate::prelude::*; use crate::prelude::*;
use crate::routing::router::{Payee, PaymentParameters}; use crate::routing::router::{Payee, PaymentParameters, RouteParametersConfig};
use crate::sign::NodeSigner; use crate::sign::NodeSigner;
use crate::sync::Mutex; use crate::sync::Mutex;
use crate::types::features::Bolt12InvoiceFeatures; use crate::types::features::Bolt12InvoiceFeatures;
@ -238,7 +238,15 @@ fn static_invoice_unknown_required_features() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(0), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(0),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
// Don't forward the invreq since we don't support retrieving the static invoice from the // Don't forward the invreq since we don't support retrieving the static invoice from the
@ -298,7 +306,15 @@ fn ignore_unexpected_static_invoice() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(0), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(0),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
// Don't forward the invreq since we don't support retrieving the static invoice from the // Don't forward the invreq since we don't support retrieving the static invoice from the
@ -415,7 +431,15 @@ fn async_receive_flow_success() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(0), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(0),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
let release_held_htlc_om = let release_held_htlc_om =
pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[2]).1; pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[2]).1;
@ -463,7 +487,15 @@ fn expired_static_invoice_fail() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(0), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(0),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
let invreq_om = nodes[0] let invreq_om = nodes[0]
@ -546,7 +578,15 @@ fn async_receive_mpp() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(1), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(1),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
let release_held_htlc_om_3_0 = let release_held_htlc_om_3_0 =
pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[3]).1; pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[3]).1;
@ -630,7 +670,15 @@ fn amount_doesnt_match_invreq() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(1), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(1),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
let release_held_htlc_om_3_0 = let release_held_htlc_om_3_0 =
pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[3]).1; pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[3]).1;
@ -859,7 +907,15 @@ fn invalid_async_receive_with_retry<F1, F2>(
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(2), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(2),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
let release_held_htlc_om_2_0 = let release_held_htlc_om_2_0 =
pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[2]).1; pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[2]).1;
@ -948,7 +1004,15 @@ fn expired_static_invoice_message_path() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(1), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(1),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
// While the invoice is unexpired, respond with release_held_htlc. // While the invoice is unexpired, respond with release_held_htlc.
@ -1052,7 +1116,15 @@ fn expired_static_invoice_payment_path() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0] nodes[0]
.node .node
.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(0), None) .pay_for_offer(
&offer,
None,
Some(amt_msat),
None,
payment_id,
Retry::Attempts(0),
RouteParametersConfig::default(),
)
.unwrap(); .unwrap();
let release_held_htlc_om = let release_held_htlc_om =
pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[2]).1; pass_async_payments_oms(static_invoice, &nodes[0], &nodes[1], &nodes[2]).1;

View file

@ -57,7 +57,7 @@ use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelType
use crate::types::features::Bolt11InvoiceFeatures; use crate::types::features::Bolt11InvoiceFeatures;
#[cfg(trampoline)] #[cfg(trampoline)]
use crate::routing::gossip::NodeId; use crate::routing::gossip::NodeId;
use crate::routing::router::{BlindedTail, FixedRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, Router}; use crate::routing::router::{BlindedTail, FixedRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, RouteParametersConfig, Router};
use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails}; use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails};
use crate::ln::msgs; use crate::ln::msgs;
use crate::ln::onion_utils; use crate::ln::onion_utils;
@ -2105,6 +2105,7 @@ where
/// # use lightning::events::{Event, EventsProvider, PaymentPurpose}; /// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
/// # use lightning::ln::channelmanager::AChannelManager; /// # use lightning::ln::channelmanager::AChannelManager;
/// # use lightning::offers::parse::Bolt12SemanticError; /// # use lightning::offers::parse::Bolt12SemanticError;
/// # use lightning::routing::router::RouteParametersConfig;
/// # /// #
/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> { /// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
/// # let channel_manager = channel_manager.get_cm(); /// # let channel_manager = channel_manager.get_cm();
@ -2152,15 +2153,16 @@ where
/// # use lightning::events::{Event, EventsProvider}; /// # use lightning::events::{Event, EventsProvider};
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry}; /// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
/// # use lightning::offers::offer::Offer; /// # use lightning::offers::offer::Offer;
/// # use lightning::routing::router::RouteParametersConfig;
/// # /// #
/// # fn example<T: AChannelManager>( /// # fn example<T: AChannelManager>(
/// # channel_manager: T, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>, /// # channel_manager: T, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
/// # payer_note: Option<String>, retry: Retry, max_total_routing_fee_msat: Option<u64> /// # payer_note: Option<String>, retry: Retry, route_params_config: RouteParametersConfig
/// # ) { /// # ) {
/// # let channel_manager = channel_manager.get_cm(); /// # let channel_manager = channel_manager.get_cm();
/// let payment_id = PaymentId([42; 32]); /// let payment_id = PaymentId([42; 32]);
/// match channel_manager.pay_for_offer( /// match channel_manager.pay_for_offer(
/// offer, quantity, amount_msats, payer_note, payment_id, retry, max_total_routing_fee_msat /// offer, quantity, amount_msats, payer_note, payment_id, retry, route_params_config
/// ) { /// ) {
/// Ok(()) => println!("Requesting invoice for offer"), /// Ok(()) => println!("Requesting invoice for offer"),
/// Err(e) => println!("Unable to request invoice for offer: {:?}", e), /// Err(e) => println!("Unable to request invoice for offer: {:?}", e),
@ -2208,16 +2210,17 @@ where
/// # use lightning::events::{Event, EventsProvider}; /// # use lightning::events::{Event, EventsProvider};
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry}; /// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
/// # use lightning::offers::parse::Bolt12SemanticError; /// # use lightning::offers::parse::Bolt12SemanticError;
/// # use lightning::routing::router::RouteParametersConfig;
/// # /// #
/// # fn example<T: AChannelManager>( /// # fn example<T: AChannelManager>(
/// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry, /// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry,
/// # max_total_routing_fee_msat: Option<u64> /// # route_params_config: RouteParametersConfig
/// # ) -> Result<(), Bolt12SemanticError> { /// # ) -> Result<(), Bolt12SemanticError> {
/// # let channel_manager = channel_manager.get_cm(); /// # let channel_manager = channel_manager.get_cm();
/// let payment_id = PaymentId([42; 32]); /// let payment_id = PaymentId([42; 32]);
/// let refund = channel_manager /// let refund = channel_manager
/// .create_refund_builder( /// .create_refund_builder(
/// amount_msats, absolute_expiry, payment_id, retry, max_total_routing_fee_msat /// amount_msats, absolute_expiry, payment_id, retry, route_params_config
/// )? /// )?
/// # ; /// # ;
/// # // Needed for compiling for c_bindings /// # // Needed for compiling for c_bindings
@ -10161,7 +10164,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
pub fn create_refund_builder( pub fn create_refund_builder(
&$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId, &$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
retry_strategy: Retry, max_total_routing_fee_msat: Option<u64> retry_strategy: Retry, route_params_config: RouteParametersConfig
) -> Result<$builder, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
let node_id = $self.get_our_node_id(); let node_id = $self.get_our_node_id();
let expanded_key = &$self.inbound_payment_key; let expanded_key = &$self.inbound_payment_key;
@ -10186,7 +10189,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry); let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
$self.pending_outbound_payments $self.pending_outbound_payments
.add_new_awaiting_invoice( .add_new_awaiting_invoice(
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, None, payment_id, expiration, retry_strategy, route_params_config, None,
) )
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?; .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
@ -10362,7 +10365,7 @@ where
pub fn pay_for_offer( pub fn pay_for_offer(
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>, &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry, payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry,
max_total_routing_fee_msat: Option<u64> route_params_config: RouteParametersConfig
) -> Result<(), Bolt12SemanticError> { ) -> Result<(), Bolt12SemanticError> {
self.pay_for_offer_intern(offer, quantity, amount_msats, payer_note, payment_id, None, |invoice_request, nonce| { self.pay_for_offer_intern(offer, quantity, amount_msats, payer_note, payment_id, None, |invoice_request, nonce| {
let expiration = StaleExpiration::TimerTicks(1); let expiration = StaleExpiration::TimerTicks(1);
@ -10373,7 +10376,7 @@ where
}; };
self.pending_outbound_payments self.pending_outbound_payments
.add_new_awaiting_invoice( .add_new_awaiting_invoice(
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, payment_id, expiration, retry_strategy, route_params_config,
Some(retryable_invoice_request) Some(retryable_invoice_request)
) )
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId) .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
@ -10606,14 +10609,14 @@ where
#[cfg(feature = "dnssec")] #[cfg(feature = "dnssec")]
pub fn pay_for_offer_from_human_readable_name( pub fn pay_for_offer_from_human_readable_name(
&self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId, &self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId,
retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>, retry_strategy: Retry, route_params_config: RouteParametersConfig,
dns_resolvers: Vec<Destination>, dns_resolvers: Vec<Destination>,
) -> Result<(), ()> { ) -> Result<(), ()> {
let (onion_message, context) = let (onion_message, context) =
self.hrn_resolver.resolve_name(payment_id, name, &*self.entropy_source)?; self.hrn_resolver.resolve_name(payment_id, name, &*self.entropy_source)?;
let reply_paths = self.create_blinded_paths(MessageContext::DNSResolver(context))?; let reply_paths = self.create_blinded_paths(MessageContext::DNSResolver(context))?;
let expiration = StaleExpiration::TimerTicks(1); let expiration = StaleExpiration::TimerTicks(1);
self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, max_total_routing_fee_msat, amount_msats)?; self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, route_params_config, amount_msats)?;
let message_params = dns_resolvers let message_params = dns_resolvers
.iter() .iter()
.flat_map(|destination| reply_paths.iter().map(move |path| (path, destination))) .flat_map(|destination| reply_paths.iter().map(move |path| (path, destination)))

View file

@ -26,7 +26,7 @@ use crate::ln::onion_utils::MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY;
use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure}; use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure};
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::prelude::*; use crate::prelude::*;
use crate::routing::router::{DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, PaymentParameters, RouteParameters}; use crate::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA};
use crate::sign::NodeSigner; use crate::sign::NodeSigner;
use crate::util::errors::APIError; use crate::util::errors::APIError;
use crate::util::ser::Writeable; use crate::util::ser::Writeable;
@ -393,7 +393,7 @@ fn bolt12_invoice_too_large_blinded_paths() {
let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap(); let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, Some(5000), None, payment_id, Retry::Attempts(0), None).unwrap(); nodes[0].node.pay_for_offer(&offer, None, Some(5000), None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap(); let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap();
nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om); nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om);

View file

@ -62,7 +62,7 @@ use crate::onion_message::messenger::{Destination, PeeledOnion, MessageSendInstr
use crate::onion_message::offers::OffersMessage; use crate::onion_message::offers::OffersMessage;
use crate::onion_message::packet::ParsedOnionMessageContents; use crate::onion_message::packet::ParsedOnionMessageContents;
use crate::routing::gossip::{NodeAlias, NodeId}; use crate::routing::gossip::{NodeAlias, NodeId};
use crate::routing::router::{PaymentParameters, RouteParameters}; use crate::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig};
use crate::sign::{NodeSigner, Recipient}; use crate::sign::{NodeSigner, Recipient};
use crate::util::ser::Writeable; use crate::util::ser::Writeable;
@ -454,7 +454,7 @@ fn creates_short_lived_refund() {
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY; let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = bob.node let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry)); assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
@ -483,7 +483,7 @@ fn creates_long_lived_refund() {
+ Duration::from_secs(1); + Duration::from_secs(1);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = bob.node let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry)); assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
@ -543,7 +543,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() {
} }
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
@ -642,7 +642,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = david.node let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_eq!(refund.amount_msats(), 10_000_000); assert_eq!(refund.amount_msats(), 10_000_000);
@ -712,7 +712,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
} }
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap(); bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
@ -771,7 +771,7 @@ fn creates_and_pays_for_refund_using_one_hop_blinded_path() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = bob.node let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_eq!(refund.amount_msats(), 10_000_000); assert_eq!(refund.amount_msats(), 10_000_000);
@ -833,7 +833,7 @@ fn pays_for_offer_without_blinded_paths() {
assert!(offer.paths().is_empty()); assert!(offer.paths().is_empty());
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap(); bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
@ -880,7 +880,7 @@ fn pays_for_refund_without_blinded_paths() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = bob.node let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.clear_paths() .clear_paths()
.build().unwrap(); .build().unwrap();
@ -960,7 +960,7 @@ fn send_invoice_requests_with_distinct_reply_path() {
} }
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
connect_peers(david, bob); connect_peers(david, bob);
@ -1035,7 +1035,7 @@ fn send_invoice_for_refund_with_distinct_reply_path() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = alice.node let refund = alice.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), alice_id); assert_ne!(refund.payer_signing_pubkey(), alice_id);
@ -1094,7 +1094,7 @@ fn creates_and_pays_for_offer_with_retry() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
} }
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap(); bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let _lost_onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let _lost_onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
@ -1166,7 +1166,7 @@ fn pays_bolt12_invoice_asynchronously() {
.build().unwrap(); .build().unwrap();
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap(); bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
@ -1256,7 +1256,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
} }
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap(); bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
@ -1314,7 +1314,7 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = bob.node let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), bob_id); assert_ne!(refund.payer_signing_pubkey(), bob_id);
@ -1397,7 +1397,7 @@ fn fails_authentication_when_handling_invoice_request() {
// Send the invoice request directly to Alice instead of using a blinded path. // Send the invoice request directly to Alice instead of using a blinded path.
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
@ -1423,7 +1423,7 @@ fn fails_authentication_when_handling_invoice_request() {
// Send the invoice request to Alice using an invalid blinded path. // Send the invoice request to Alice using an invalid blinded path.
let payment_id = PaymentId([2; 32]); let payment_id = PaymentId([2; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
@ -1500,7 +1500,7 @@ fn fails_authentication_when_handling_invoice_for_offer() {
// Initiate an invoice request, but abandon tracking it. // Initiate an invoice request, but abandon tracking it.
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
david.node.abandon_payment(payment_id); david.node.abandon_payment(payment_id);
get_event!(david, Event::PaymentFailed); get_event!(david, Event::PaymentFailed);
@ -1517,7 +1517,7 @@ fn fails_authentication_when_handling_invoice_for_offer() {
}; };
let payment_id = PaymentId([2; 32]); let payment_id = PaymentId([2; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
@ -1597,7 +1597,7 @@ fn fails_authentication_when_handling_invoice_for_refund() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = david.node let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), david_id); assert_ne!(refund.payer_signing_pubkey(), david_id);
@ -1631,7 +1631,7 @@ fn fails_authentication_when_handling_invoice_for_refund() {
let invalid_path = refund.paths().first().unwrap().clone(); let invalid_path = refund.paths().first().unwrap().clone();
let payment_id = PaymentId([2; 32]); let payment_id = PaymentId([2; 32]);
let refund = david.node let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), david_id); assert_ne!(refund.payer_signing_pubkey(), david_id);
@ -1701,7 +1701,7 @@ fn fails_creating_or_paying_for_offer_without_connected_peers() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) { match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()) {
Ok(_) => panic!("Expected error"), Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths), Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
} }
@ -1714,7 +1714,7 @@ fn fails_creating_or_paying_for_offer_without_connected_peers() {
assert!( assert!(
david.node.pay_for_offer( david.node.pay_for_offer(
&offer, None, None, None, payment_id, Retry::Attempts(0), None &offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
).is_ok() ).is_ok()
); );
@ -1758,7 +1758,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
let absolute_expiry = david.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY; let absolute_expiry = david.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
match david.node.create_refund_builder( match david.node.create_refund_builder(
10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None 10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
) { ) {
Ok(_) => panic!("Expected error"), Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths), Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
@ -1769,7 +1769,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
reconnect_nodes(args); reconnect_nodes(args);
let refund = david.node let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
@ -1805,7 +1805,7 @@ fn fails_creating_invoice_request_for_unsupported_chain() {
.build().unwrap(); .build().unwrap();
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
match bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) { match bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()) {
Ok(_) => panic!("Expected error"), Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain), Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
} }
@ -1827,7 +1827,7 @@ fn fails_sending_invoice_with_unsupported_chain_for_refund() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = bob.node let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.chain(Network::Signet) .chain(Network::Signet)
.build().unwrap(); .build().unwrap();
@ -1864,7 +1864,7 @@ fn fails_creating_invoice_request_without_blinded_reply_path() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) { match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()) {
Ok(_) => panic!("Expected error"), Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths), Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
} }
@ -1899,12 +1899,12 @@ fn fails_creating_invoice_request_with_duplicate_payment_id() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
assert!( assert!(
david.node.pay_for_offer( david.node.pay_for_offer(
&offer, None, None, None, payment_id, Retry::Attempts(0), None &offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
).is_ok() ).is_ok()
); );
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) { match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()) {
Ok(_) => panic!("Expected error"), Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId), Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId),
} }
@ -1925,13 +1925,13 @@ fn fails_creating_refund_with_duplicate_payment_id() {
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
assert!( assert!(
nodes[0].node.create_refund_builder( nodes[0].node.create_refund_builder(
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None 10_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
).is_ok() ).is_ok()
); );
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
match nodes[0].node.create_refund_builder( match nodes[0].node.create_refund_builder(
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None 10_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
) { ) {
Ok(_) => panic!("Expected error"), Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId), Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId),
@ -1983,7 +1983,7 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {
.build().unwrap(); .build().unwrap();
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
connect_peers(david, bob); connect_peers(david, bob);
@ -2051,7 +2051,7 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_refund() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = david.node let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
@ -2100,7 +2100,7 @@ fn fails_paying_invoice_more_than_once() {
let absolute_expiry = Duration::from_secs(u64::MAX); let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
let refund = david.node let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None) .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap() .unwrap()
.build().unwrap(); .build().unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
@ -2192,7 +2192,7 @@ fn fails_paying_invoice_with_unknown_required_features() {
.build().unwrap(); .build().unwrap();
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap(); .unwrap();
connect_peers(david, bob); connect_peers(david, bob);
@ -2269,7 +2269,7 @@ fn rejects_keysend_to_non_static_invoice_path() {
let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap(); let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
let amt_msat = 5000; let amt_msat = 5000;
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(1), None).unwrap(); nodes[0].node.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(1), RouteParametersConfig::default()).unwrap();
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap(); let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap();
nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om); nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om);
let invoice_om = nodes[1].onion_messenger.next_onion_message_for_peer(nodes[0].node.get_our_node_id()).unwrap(); let invoice_om = nodes[1].onion_messenger.next_onion_message_for_peer(nodes[0].node.get_our_node_id()).unwrap();
@ -2354,7 +2354,7 @@ fn no_double_pay_with_stale_channelmanager() {
assert!(offer.paths().is_empty()); assert!(offer.paths().is_empty());
let payment_id = PaymentId([1; 32]); let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap(); nodes[0].node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), RouteParametersConfig::default()).unwrap();
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(bob_id).unwrap(); let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(bob_id).unwrap();

View file

@ -24,7 +24,7 @@ use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason};
use crate::offers::invoice::Bolt12Invoice; use crate::offers::invoice::Bolt12Invoice;
use crate::offers::invoice_request::InvoiceRequest; use crate::offers::invoice_request::InvoiceRequest;
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router}; use crate::routing::router::{BlindedTail, InFlightHtlcs, RouteParametersConfig, Path, PaymentParameters, Route, RouteParameters, Router};
use crate::sign::{EntropySource, NodeSigner, Recipient}; use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::util::errors::APIError; use crate::util::errors::APIError;
use crate::util::logger::Logger; use crate::util::logger::Logger;
@ -62,7 +62,7 @@ pub(crate) enum PendingOutboundPayment {
AwaitingOffer { AwaitingOffer {
expiration: StaleExpiration, expiration: StaleExpiration,
retry_strategy: Retry, retry_strategy: Retry,
max_total_routing_fee_msat: Option<u64>, route_params_config: RouteParametersConfig,
/// Human Readable Names-originated payments should always specify an explicit amount to /// Human Readable Names-originated payments should always specify an explicit amount to
/// send up-front, which we track here and enforce once we receive the offer. /// send up-front, which we track here and enforce once we receive the offer.
amount_msats: u64, amount_msats: u64,
@ -70,7 +70,7 @@ pub(crate) enum PendingOutboundPayment {
AwaitingInvoice { AwaitingInvoice {
expiration: StaleExpiration, expiration: StaleExpiration,
retry_strategy: Retry, retry_strategy: Retry,
max_total_routing_fee_msat: Option<u64>, route_params_config: RouteParametersConfig,
retryable_invoice_request: Option<RetryableInvoiceRequest> retryable_invoice_request: Option<RetryableInvoiceRequest>
}, },
// This state will never be persisted to disk because we transition from `AwaitingInvoice` to // This state will never be persisted to disk because we transition from `AwaitingInvoice` to
@ -79,9 +79,10 @@ pub(crate) enum PendingOutboundPayment {
InvoiceReceived { InvoiceReceived {
payment_hash: PaymentHash, payment_hash: PaymentHash,
retry_strategy: Retry, retry_strategy: Retry,
// Note this field is currently just replicated from AwaitingInvoice but not actually // Currently unused, but replicated from `AwaitingInvoice` to avoid potential
// used anywhere. // race conditions where this field might be missing upon reload. It may be required
max_total_routing_fee_msat: Option<u64>, // for future retries.
route_params_config: RouteParametersConfig,
}, },
// This state applies when we are paying an often-offline recipient and another node on the // This state applies when we are paying an often-offline recipient and another node on the
// network served us a static invoice on the recipient's behalf in response to our invoice // network served us a static invoice on the recipient's behalf in response to our invoice
@ -862,19 +863,19 @@ impl OutboundPayments {
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>, SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
{ {
let payment_hash = invoice.payment_hash(); let payment_hash = invoice.payment_hash();
let max_total_routing_fee_msat; let params_config;
let retry_strategy; let retry_strategy;
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
hash_map::Entry::Occupied(entry) => match entry.get() { hash_map::Entry::Occupied(entry) => match entry.get() {
PendingOutboundPayment::AwaitingInvoice { PendingOutboundPayment::AwaitingInvoice {
retry_strategy: retry, max_total_routing_fee_msat: max_total_fee, .. retry_strategy: retry, route_params_config, ..
} => { } => {
retry_strategy = *retry; retry_strategy = *retry;
max_total_routing_fee_msat = *max_total_fee; params_config = *route_params_config;
*entry.into_mut() = PendingOutboundPayment::InvoiceReceived { *entry.into_mut() = PendingOutboundPayment::InvoiceReceived {
payment_hash, payment_hash,
retry_strategy: *retry, retry_strategy: *retry,
max_total_routing_fee_msat, route_params_config: *route_params_config,
}; };
}, },
_ => return Err(Bolt12PaymentError::DuplicateInvoice), _ => return Err(Bolt12PaymentError::DuplicateInvoice),
@ -890,9 +891,10 @@ impl OutboundPayments {
} }
let mut route_params = RouteParameters::from_payment_params_and_value( let mut route_params = RouteParameters::from_payment_params_and_value(
PaymentParameters::from_bolt12_invoice(&invoice), invoice.amount_msats() PaymentParameters::from_bolt12_invoice(&invoice)
.with_user_config_ignoring_fee_limit(params_config), invoice.amount_msats()
); );
if let Some(max_fee_msat) = max_total_routing_fee_msat { if let Some(max_fee_msat) = params_config.max_total_routing_fee_msat {
route_params.max_total_routing_fee_msat = Some(max_fee_msat); route_params.max_total_routing_fee_msat = Some(max_fee_msat);
} }
self.send_payment_for_bolt12_invoice_internal( self.send_payment_for_bolt12_invoice_internal(
@ -1035,7 +1037,7 @@ impl OutboundPayments {
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
hash_map::Entry::Occupied(mut entry) => match entry.get_mut() { hash_map::Entry::Occupied(mut entry) => match entry.get_mut() {
PendingOutboundPayment::AwaitingInvoice { PendingOutboundPayment::AwaitingInvoice {
retry_strategy, retryable_invoice_request, max_total_routing_fee_msat, .. retry_strategy, retryable_invoice_request, route_params_config, ..
} => { } => {
let invreq = &retryable_invoice_request let invreq = &retryable_invoice_request
.as_ref() .as_ref()
@ -1065,9 +1067,10 @@ impl OutboundPayments {
}; };
let keysend_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes()); let keysend_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes());
let payment_hash = PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array()); let payment_hash = PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array());
let pay_params = PaymentParameters::from_static_invoice(invoice); let pay_params = PaymentParameters::from_static_invoice(invoice)
.with_user_config_ignoring_fee_limit(*route_params_config);
let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat); let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat);
route_params.max_total_routing_fee_msat = *max_total_routing_fee_msat; route_params.max_total_routing_fee_msat = route_params_config.max_total_routing_fee_msat;
if let Err(()) = onion_utils::set_max_path_length( if let Err(()) = onion_utils::set_max_path_length(
&mut route_params, &RecipientOnionFields::spontaneous_empty(), Some(keysend_preimage), &mut route_params, &RecipientOnionFields::spontaneous_empty(), Some(keysend_preimage),
@ -1710,7 +1713,7 @@ impl OutboundPayments {
#[cfg(feature = "dnssec")] #[cfg(feature = "dnssec")]
pub(super) fn add_new_awaiting_offer( pub(super) fn add_new_awaiting_offer(
&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry, &self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry,
max_total_routing_fee_msat: Option<u64>, amount_msats: u64, route_params_config: RouteParametersConfig, amount_msats: u64,
) -> Result<(), ()> { ) -> Result<(), ()> {
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap(); let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
match pending_outbounds.entry(payment_id) { match pending_outbounds.entry(payment_id) {
@ -1719,7 +1722,7 @@ impl OutboundPayments {
entry.insert(PendingOutboundPayment::AwaitingOffer { entry.insert(PendingOutboundPayment::AwaitingOffer {
expiration, expiration,
retry_strategy, retry_strategy,
max_total_routing_fee_msat, route_params_config,
amount_msats, amount_msats,
}); });
@ -1746,12 +1749,12 @@ impl OutboundPayments {
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
hash_map::Entry::Occupied(entry) => match entry.get() { hash_map::Entry::Occupied(entry) => match entry.get() {
PendingOutboundPayment::AwaitingOffer { PendingOutboundPayment::AwaitingOffer {
expiration, retry_strategy, max_total_routing_fee_msat, .. expiration, retry_strategy, route_params_config, ..
} => { } => {
let mut new_val = PendingOutboundPayment::AwaitingInvoice { let mut new_val = PendingOutboundPayment::AwaitingInvoice {
expiration: *expiration, expiration: *expiration,
retry_strategy: *retry_strategy, retry_strategy: *retry_strategy,
max_total_routing_fee_msat: *max_total_routing_fee_msat, route_params_config: *route_params_config,
retryable_invoice_request, retryable_invoice_request,
}; };
core::mem::swap(&mut new_val, entry.into_mut()); core::mem::swap(&mut new_val, entry.into_mut());
@ -1765,7 +1768,7 @@ impl OutboundPayments {
pub(super) fn add_new_awaiting_invoice( pub(super) fn add_new_awaiting_invoice(
&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry, &self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry,
max_total_routing_fee_msat: Option<u64>, retryable_invoice_request: Option<RetryableInvoiceRequest> route_params_config: RouteParametersConfig, retryable_invoice_request: Option<RetryableInvoiceRequest>
) -> Result<(), ()> { ) -> Result<(), ()> {
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap(); let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
match pending_outbounds.entry(payment_id) { match pending_outbounds.entry(payment_id) {
@ -1777,7 +1780,7 @@ impl OutboundPayments {
entry.insert(PendingOutboundPayment::AwaitingInvoice { entry.insert(PendingOutboundPayment::AwaitingInvoice {
expiration, expiration,
retry_strategy, retry_strategy,
max_total_routing_fee_msat, route_params_config,
retryable_invoice_request, retryable_invoice_request,
}); });
@ -2411,13 +2414,35 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
(5, AwaitingInvoice) => { (5, AwaitingInvoice) => {
(0, expiration, required), (0, expiration, required),
(2, retry_strategy, required), (2, retry_strategy, required),
(4, max_total_routing_fee_msat, option), (4, _max_total_routing_fee_msat, (legacy, u64,
|us: &PendingOutboundPayment| match us {
PendingOutboundPayment::AwaitingInvoice { route_params_config, .. } => route_params_config.max_total_routing_fee_msat,
_ => None,
}
)),
(5, retryable_invoice_request, option), (5, retryable_invoice_request, option),
(7, route_params_config, (default_value, (
_max_total_routing_fee_msat.map_or(
RouteParametersConfig::default(),
|fee_msat| RouteParametersConfig::default().with_max_total_routing_fee_msat(fee_msat)
)
))),
}, },
(7, InvoiceReceived) => { (7, InvoiceReceived) => {
(0, payment_hash, required), (0, payment_hash, required),
(2, retry_strategy, required), (2, retry_strategy, required),
(4, max_total_routing_fee_msat, option), (4, _max_total_routing_fee_msat, (legacy, u64,
|us: &PendingOutboundPayment| match us {
PendingOutboundPayment::InvoiceReceived { route_params_config, .. } => route_params_config.max_total_routing_fee_msat,
_ => None,
}
)),
(5, route_params_config, (default_value, (
_max_total_routing_fee_msat.map_or(
RouteParametersConfig::default(),
|fee_msat| RouteParametersConfig::default().with_max_total_routing_fee_msat(fee_msat)
)
))),
}, },
// Added in 0.1. Prior versions will drop these outbounds on downgrade, which is safe because no // Added in 0.1. Prior versions will drop these outbounds on downgrade, which is safe because no
// HTLCs are in-flight. // HTLCs are in-flight.
@ -2433,7 +2458,18 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
(11, AwaitingOffer) => { (11, AwaitingOffer) => {
(0, expiration, required), (0, expiration, required),
(2, retry_strategy, required), (2, retry_strategy, required),
(4, max_total_routing_fee_msat, option), (4, _max_total_routing_fee_msat, (legacy, u64,
|us: &PendingOutboundPayment| match us {
PendingOutboundPayment::AwaitingOffer { route_params_config, .. } => route_params_config.max_total_routing_fee_msat,
_ => None,
}
)),
(5, route_params_config, (default_value, (
_max_total_routing_fee_msat.map_or(
RouteParametersConfig::default(),
|fee_msat| RouteParametersConfig::default().with_max_total_routing_fee_msat(fee_msat)
)
))),
(6, amount_msats, required), (6, amount_msats, required),
}, },
); );
@ -2459,7 +2495,7 @@ mod tests {
use crate::offers::offer::OfferBuilder; use crate::offers::offer::OfferBuilder;
use crate::offers::test_utils::*; use crate::offers::test_utils::*;
use crate::routing::gossip::NetworkGraph; use crate::routing::gossip::NetworkGraph;
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters}; use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, RouteParametersConfig};
use crate::sync::{Arc, Mutex, RwLock}; use crate::sync::{Arc, Mutex, RwLock};
use crate::util::errors::APIError; use crate::util::errors::APIError;
use crate::util::hash_tables::new_hash_map; use crate::util::hash_tables::new_hash_map;
@ -2670,7 +2706,7 @@ mod tests {
assert!(!outbound_payments.has_pending_payments()); assert!(!outbound_payments.has_pending_payments());
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
@ -2700,14 +2736,14 @@ mod tests {
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_err() ).is_err()
); );
} }
@ -2723,7 +2759,7 @@ mod tests {
assert!(!outbound_payments.has_pending_payments()); assert!(!outbound_payments.has_pending_payments());
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
@ -2753,14 +2789,14 @@ mod tests {
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_err() ).is_err()
); );
} }
@ -2775,7 +2811,7 @@ mod tests {
assert!(!outbound_payments.has_pending_payments()); assert!(!outbound_payments.has_pending_payments());
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
@ -2813,7 +2849,7 @@ mod tests {
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), None, None, payment_id, expiration, Retry::Attempts(0), RouteParametersConfig::default(), None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
@ -2874,10 +2910,12 @@ mod tests {
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let route_params_config = RouteParametersConfig::default().with_max_total_routing_fee_msat(invoice.amount_msats() / 100 + 50_000);
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), payment_id, expiration, Retry::Attempts(0),
Some(invoice.amount_msats() / 100 + 50_000), None, route_params_config, None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());
@ -2974,9 +3012,11 @@ mod tests {
assert!(!outbound_payments.has_pending_payments()); assert!(!outbound_payments.has_pending_payments());
assert!(pending_events.lock().unwrap().is_empty()); assert!(pending_events.lock().unwrap().is_empty());
let route_params_config = RouteParametersConfig::default().with_max_total_routing_fee_msat(1234);
assert!( assert!(
outbound_payments.add_new_awaiting_invoice( outbound_payments.add_new_awaiting_invoice(
payment_id, expiration, Retry::Attempts(0), Some(1234), None, payment_id, expiration, Retry::Attempts(0), route_params_config, None,
).is_ok() ).is_ok()
); );
assert!(outbound_payments.has_pending_payments()); assert!(outbound_payments.has_pending_payments());

View file

@ -943,6 +943,21 @@ impl PaymentParameters {
} }
} }
/// Updates the parameters with the given route parameters configuration.
///
/// Note:
/// We *do not* apply `max_total_routing_fee_msat` here, as it is unique to each route.
/// Instead, we apply only the parameters that are common across multiple route-finding sessions
/// for a payment across retries.
pub(crate) fn with_user_config_ignoring_fee_limit(self, params_config: RouteParametersConfig) -> Self {
Self {
max_total_cltv_expiry_delta: params_config.max_total_cltv_expiry_delta,
max_path_count: params_config.max_path_count,
max_channel_saturation_power_of_half: params_config.max_channel_saturation_power_of_half,
..self
}
}
/// Includes the payee's features. Errors if the parameters were not initialized with /// Includes the payee's features. Errors if the parameters were not initialized with
/// [`PaymentParameters::from_bolt12_invoice`]. /// [`PaymentParameters::from_bolt12_invoice`].
/// ///
@ -1030,6 +1045,93 @@ impl PaymentParameters {
} }
} }
/// A struct for configuring parameters for routing the payment.
#[derive(Clone, Copy)]
pub struct RouteParametersConfig {
/// The maximum total fees, in millisatoshi, that may accrue during route finding.
///
/// This limit also applies to the total fees that may arise while retrying failed payment
/// paths.
///
/// Note that values below a few sats may result in some paths being spuriously ignored.
///
/// Defaults to 1% of the payment amount + 50 sats
pub max_total_routing_fee_msat: Option<u64>,
/// The maximum total CLTV delta we accept for the route.
/// Defaults to [`DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA`].
pub max_total_cltv_expiry_delta: u32,
/// The maximum number of paths that may be used by (MPP) payments.
/// Defaults to [`DEFAULT_MAX_PATH_COUNT`].
pub max_path_count: u8,
/// Selects the maximum share of a channel's total capacity which will be sent over a channel,
/// as a power of 1/2. A higher value prefers to send the payment using more MPP parts whereas
/// a lower value prefers to send larger MPP parts, potentially saturating channels and
/// increasing failure probability for those paths.
///
/// Note that this restriction will be relaxed during pathfinding after paths which meet this
/// restriction have been found. While paths which meet this criteria will be searched for, it
/// is ultimately up to the scorer to select them over other paths.
///
/// A value of 0 will allow payments up to and including a channel's total announced usable
/// capacity, a value of one will only use up to half its capacity, two 1/4, etc.
///
/// Default value: 2
pub max_channel_saturation_power_of_half: u8,
}
impl_writeable_tlv_based!(RouteParametersConfig, {
(1, max_total_routing_fee_msat, option),
(3, max_total_cltv_expiry_delta, required),
(5, max_path_count, required),
(7, max_channel_saturation_power_of_half, required),
});
impl RouteParametersConfig {
/// Set the maximum total fees, in millisatoshi, that may accrue during route finding.
///
/// This is not exported to bindings users since bindings don't support move semantics
pub fn with_max_total_routing_fee_msat(self, fee_msat: u64) -> Self {
Self { max_total_routing_fee_msat: Some(fee_msat), ..self }
}
/// Includes a limit for the total CLTV expiry delta which is considered during routing
///
/// This is not exported to bindings users since bindings don't support move semantics
pub fn with_max_total_cltv_expiry_delta(self, max_total_cltv_expiry_delta: u32) -> Self {
Self { max_total_cltv_expiry_delta, ..self }
}
/// Includes a limit for the maximum number of payment paths that may be used.
///
/// This is not exported to bindings users since bindings don't support move semantics
pub fn with_max_path_count(self, max_path_count: u8) -> Self {
Self { max_path_count, ..self }
}
/// Includes a limit for the maximum share of a channel's total capacity that can be sent over, as
/// a power of 1/2. See [`PaymentParameters::max_channel_saturation_power_of_half`].
///
/// This is not exported to bindings users since bindings don't support move semantics
pub fn with_max_channel_saturation_power_of_half(self, max_channel_saturation_power_of_half: u8) -> Self {
Self { max_channel_saturation_power_of_half, ..self }
}
}
impl Default for RouteParametersConfig {
/// Initates an new set of route parameter configs with default parameters.
fn default() -> Self {
Self {
max_total_routing_fee_msat: None,
max_total_cltv_expiry_delta: DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
max_path_count: DEFAULT_MAX_PATH_COUNT,
max_channel_saturation_power_of_half: DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF,
}
}
}
/// The recipient of a payment, differing based on whether they've hidden their identity with route /// The recipient of a payment, differing based on whether they've hidden their identity with route
/// blinding. /// blinding.
#[derive(Clone, Debug, Hash, PartialEq, Eq)] #[derive(Clone, Debug, Hash, PartialEq, Eq)]

View file

@ -40,7 +40,7 @@ macro_rules! _encode_tlv {
} }
}; };
($stream: expr, $optional_type: expr, $optional_field: expr, (legacy, $fieldty: ty, $write: expr) $(, $self: ident)?) => { ($stream: expr, $optional_type: expr, $optional_field: expr, (legacy, $fieldty: ty, $write: expr) $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $optional_type, $write($($self)?), option); $crate::_encode_tlv!($stream, $optional_type, { let value: Option<$fieldty> = $write($($self)?); value }, option);
}; };
($stream: expr, $type: expr, $field: expr, optional_vec $(, $self: ident)?) => { ($stream: expr, $type: expr, $field: expr, optional_vec $(, $self: ident)?) => {
if !$field.is_empty() { if !$field.is_empty() {