Add create_blinded_paths to MessageRouter

The MessageRouter trait is used to find an OnionMessagePath to a
Destination (e.g., to a BlindedPath). Expand the interface with a
create_blinded_paths method for creating such paths to a recipient.
Provide a default implementation creating two-hop blinded paths where
the recipient's peers serve as introduction nodes.
This commit is contained in:
Jeffrey Czyz 2023-12-07 15:48:43 -06:00
parent ffb0d83298
commit 97049daac2
No known key found for this signature in database
GPG Key ID: 3A4E08275D5E96D2
3 changed files with 76 additions and 6 deletions

View File

@ -1,17 +1,18 @@
// Imports that need to be added manually
use bitcoin::bech32::u5;
use bitcoin::blockdata::script::ScriptBuf;
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, self};
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
use bitcoin::secp256k1::schnorr;
use lightning::sign::{Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider};
use lightning::blinded_path::BlindedPath;
use lightning::ln::features::InitFeatures;
use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler};
use lightning::ln::script::ShutdownScript;
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::sign::{Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider};
use lightning::util::test_channel_signer::TestChannelSigner;
use lightning::util::logger::Logger;
use lightning::util::ser::{Readable, Writeable, Writer};
@ -82,6 +83,15 @@ impl MessageRouter for TestMessageRouter {
first_node_addresses: None,
})
}
fn create_blinded_paths<
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
>(
&self, _recipient: PublicKey, _peers: Vec<PublicKey>, _entropy_source: &ES,
_secp_ctx: &Secp256k1<T>
) -> Result<Vec<BlindedPath>, ()> {
unreachable!()
}
}
struct TestOffersMessageHandler {}

View File

@ -13,14 +13,14 @@ use crate::blinded_path::BlindedPath;
use crate::events::{Event, EventsProvider};
use crate::ln::features::InitFeatures;
use crate::ln::msgs::{self, DecodeError, OnionMessageHandler, SocketAddress};
use crate::sign::{NodeSigner, Recipient};
use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer};
use crate::util::test_utils;
use super::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, PendingOnionMessage, SendError};
use bitcoin::network::constants::Network;
use bitcoin::hashes::hex::FromHex;
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self};
use crate::io;
use crate::io_extras::read_to_end;
@ -55,6 +55,15 @@ impl MessageRouter for TestMessageRouter {
Some(vec![SocketAddress::TcpIpV4 { addr: [127, 0, 0, 1], port: 1000 }]),
})
}
fn create_blinded_paths<
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
>(
&self, _recipient: PublicKey, _peers: Vec<PublicKey>, _entropy_source: &ES,
_secp_ctx: &Secp256k1<T>
) -> Result<Vec<BlindedPath>, ()> {
unreachable!()
}
}
struct TestOffersMessageHandler {}

View File

@ -64,9 +64,9 @@ pub(super) const MAX_TIMER_TICKS: usize = 2;
/// # extern crate bitcoin;
/// # use bitcoin::hashes::_export::_core::time::Duration;
/// # use bitcoin::hashes::hex::FromHex;
/// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
/// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self};
/// # use lightning::blinded_path::BlindedPath;
/// # use lightning::sign::KeysManager;
/// # use lightning::sign::{EntropySource, KeysManager};
/// # use lightning::ln::peer_handler::IgnoringMessageHandler;
/// # use lightning::onion_message::{OnionMessageContents, Destination, MessageRouter, OnionMessagePath, OnionMessenger};
/// # use lightning::util::logger::{Logger, Record};
@ -90,6 +90,11 @@ pub(super) const MAX_TIMER_TICKS: usize = 2;
/// # first_node_addresses: None,
/// # })
/// # }
/// # fn create_blinded_paths<ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification>(
/// # &self, _recipient: PublicKey, _peers: Vec<PublicKey>, _entropy_source: &ES, _secp_ctx: &Secp256k1<T>
/// # ) -> Result<Vec<BlindedPath>, ()> {
/// # unreachable!()
/// # }
/// # }
/// # let seed = [42u8; 32];
/// # let time = Duration::from_secs(123456);
@ -270,6 +275,15 @@ pub trait MessageRouter {
fn find_path(
&self, sender: PublicKey, peers: Vec<PublicKey>, destination: Destination
) -> Result<OnionMessagePath, ()>;
/// Creates [`BlindedPath`]s to the `recipient` node. The nodes in `peers` are assumed to be
/// direct peers with the `recipient`.
fn create_blinded_paths<
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
>(
&self, recipient: PublicKey, peers: Vec<PublicKey>, entropy_source: &ES,
secp_ctx: &Secp256k1<T>
) -> Result<Vec<BlindedPath>, ()>;
}
/// A [`MessageRouter`] that can only route to a directly connected [`Destination`].
@ -321,6 +335,43 @@ where
}
}
}
fn create_blinded_paths<
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
>(
&self, recipient: PublicKey, peers: Vec<PublicKey>, entropy_source: &ES,
secp_ctx: &Secp256k1<T>
) -> Result<Vec<BlindedPath>, ()> {
// Limit the number of blinded paths that are computed.
const MAX_PATHS: usize = 3;
// Ensure peers have at least three channels so that it is more difficult to infer the
// recipient's node_id.
const MIN_PEER_CHANNELS: usize = 3;
let network_graph = self.network_graph.deref().read_only();
let paths = peers.into_iter()
// Limit to peers with announced channels
.filter(|pubkey|
network_graph
.node(&NodeId::from_pubkey(&pubkey))
.map(|info| &info.channels[..])
.map(|channels| channels.len() >= MIN_PEER_CHANNELS)
.unwrap_or(false)
)
.map(|pubkey| vec![pubkey, recipient])
.map(|node_pks| BlindedPath::new_for_message(&node_pks, entropy_source, secp_ctx))
.take(MAX_PATHS)
.collect::<Result<Vec<_>, _>>();
match paths {
Ok(paths) if !paths.is_empty() => Ok(paths),
_ => {
BlindedPath::one_hop_for_message(recipient, entropy_source, secp_ctx)
.map(|path| vec![path])
},
}
}
}
/// A path for sending an [`OnionMessage`].