Skip to content

Commit

Permalink
messenger: fix PeerConnected empty features bug
Browse files Browse the repository at this point in the history
If we need to connect directly to the introduction node provided by an offer,
LNDK's onion messenger will receive a PeerConnected event to process this new
connection. When we first look at that new peer, the features map is empty,
and LNDK decides onion support must be "false". This botches future payment
attempts, because the onion messenger thinks that this peer doesn't support
onion messaging, and shouldn't be considered in future payment paths. To fix
this, we add a little wait loop that looks for a non-empty map.
  • Loading branch information
orbitalturtle committed Jul 2, 2024
1 parent 6b2171f commit 2f1dd02
Showing 1 changed file with 55 additions and 2 deletions.
57 changes: 55 additions & 2 deletions src/onion_messenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ use std::io::Cursor;
use std::marker::Copy;
use std::str::FromStr;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::{select, time, time::Duration, time::Interval};
use tokio::time::{sleep, timeout, Duration};
use tokio::{select, time, time::Interval};
use tonic_lnd::{
lnrpc::peer_event::EventType::PeerOffline, lnrpc::peer_event::EventType::PeerOnline,
lnrpc::CustomMessage, lnrpc::PeerEvent, lnrpc::SendCustomMessageRequest,
Expand Down Expand Up @@ -282,7 +283,26 @@ async fn lookup_onion_support(pubkey: &PublicKey, client: &mut tonic_lnd::Lightn
continue;
}

return features_support_onion_messages(&peer.features);
// Sometimes if the connection to the peer is very new, we have to wait for the
// features map to populate as non-empty.
let check_empty_timeout = 5;
let features = match timeout(
Duration::from_secs(check_empty_timeout),
check_empty_features(pubkey, client.clone()),
)
.await
{
Ok(features) => features,
Err(_) => {
warn!(
"Did not get non-empty feature set from peer {} set in {} seconds.",
peer.pub_key, check_empty_timeout
);
peer.features
}
};

return features_support_onion_messages(&features);
}

warn!("Peer {pubkey} not found in current set of peers, assuming no onion support.");
Expand All @@ -295,6 +315,39 @@ async fn lookup_onion_support(pubkey: &PublicKey, client: &mut tonic_lnd::Lightn
}
}

// check_empty_features repeatedly looks up the peer's feature set until it returns a non-empty
// map. Sometimes if a peer is new, LND needs a little time to update the feature set.
async fn check_empty_features(
pubkey: &PublicKey,
mut client: LightningClient,
) -> HashMap<u32, tonic_lnd::lnrpc::Feature> {
loop {
match client
.list_peers(tonic_lnd::lnrpc::ListPeersRequest {
latest_error: false,
})
.await
{
Ok(peers) => {
for peer in peers.into_inner().peers {
if peer.pub_key != pubkey.to_string() {
continue;
}

if !peer.features.is_empty() {
return peer.features;
}
}
}
Err(_) => {
warn!("error connecting to listpeers");
continue;
}
};
sleep(Duration::from_millis(500)).await;
}
}

#[derive(Debug)]
/// ProducerError represents the exit of a producing loop.
enum ProducerError {
Expand Down

0 comments on commit 2f1dd02

Please sign in to comment.