Skip to content

Commit

Permalink
fix(tests): rename amount_received_msat to amount_msat
Browse files Browse the repository at this point in the history
Signed-off-by: Tarek <[email protected]>
  • Loading branch information
tareknaser authored and vincenzopalazzo committed Jul 29, 2024
1 parent bc73abf commit b215e0b
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 126 deletions.
12 changes: 7 additions & 5 deletions barq-common/src/algorithms/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
pub mod direct;
pub mod probabilistic;

use crate::strategy::StrategyKind;

use super::strategy::Strategy;

pub fn get_algorithm(name: &str) -> Option<Box<dyn Strategy>> {
match name {
"direct" => Some(Box::new(direct::Direct::new())),
"probabilistic" => Some(Box::new(probabilistic::LDKRoutingStrategy::default())),
_ => None,
pub fn get_algorithm(strategy: &StrategyKind) -> Option<Box<dyn Strategy>> {
match strategy {
StrategyKind::Direct => Some(Box::new(direct::Direct::new())),
#[allow(clippy::box_default)]
StrategyKind::Probabilistic => Some(Box::new(probabilistic::LDKRoutingStrategy::default())),
}
}
10 changes: 5 additions & 5 deletions barq-common/src/algorithms/probabilistic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ where
/// required for LDK routing.
fn can_apply(&self, input: &RouteInput) -> Result<bool> {
if input.graph.has_p2p_info() {
Ok(true)
} else {
Err(anyhow::anyhow!(
"The network graph does not have peer-to-peer information required for LDK routing"
))
return Ok(true);
}
log::warn!(
"The network graph does not have peer-to-peer information required for LDK routing"
);
Ok(false)
}

fn route(&self, input: &RouteInput) -> Result<RouteOutput> {
Expand Down
61 changes: 36 additions & 25 deletions barq-common/src/strategy.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
use std::str::FromStr;

use anyhow::Result;
use serde::{Deserialize, Serialize};

use crate::algorithms::direct::Direct;
// FIXME: this should be a builder pattern.
use crate::algorithms::get_algorithm;
use crate::graph::NetworkGraph;

#[derive(Debug)]
pub enum StrategyKind {
Direct,
Probabilistic,
}

impl FromStr for StrategyKind {
type Err = anyhow::Error;

fn from_str(s: &str) -> anyhow::Result<Self> {
match s.to_lowercase().as_str() {
"direct" => Ok(Self::Direct),
"probabilistic" => Ok(Self::Probabilistic),
_ => anyhow::bail!("Strategy `{s}` not found"),
}
}
}

impl Default for StrategyKind {
fn default() -> Self {
Self::Direct
}
}

/// The `Strategy` trait defines an interface for routing strategies used within
/// Barq.
///
Expand Down Expand Up @@ -50,10 +76,7 @@ pub struct RouteInput {
/// The network graph used for routing
pub graph: Box<dyn NetworkGraph>,
/// Strategy to use for routing
///
/// Note: This field is optional. If not provided, the router will select
/// the best strategy based on the input and context.
pub strategy: Option<String>,
pub strategy: StrategyKind,
}

/// Represents the output of a routing strategy
Expand Down Expand Up @@ -86,8 +109,9 @@ impl Default for Router {
/// - [`crate::algorithms::direct::Direct`]
fn default() -> Self {
// SAFETY: We can safely unwrap here because we know that the algorithm exists
let direct = get_algorithm("direct").expect("Failed to get direct algorithm");
let strategies = vec![direct];
let direct = get_algorithm(&StrategyKind::Direct).unwrap();
let probabilistic = get_algorithm(&StrategyKind::Probabilistic).unwrap();
let strategies = vec![direct, probabilistic];

Router { strategies }
}
Expand All @@ -102,32 +126,19 @@ impl Router {
}

/// Execute the routing process using the best strategy based on input
///
/// If the user specifies a strategy in the input, the router will use that
/// strategy. Otherwise, it will select the best strategy based on the input
/// and context.
pub fn execute(&self, input: &RouteInput) -> Result<RouteOutput> {
// Either the user specifies a strategy or we select the best one
let best_strategy = match input.strategy.clone() {
Some(strategy) => {
let strategy = get_algorithm(&strategy)
.ok_or_else(|| anyhow::anyhow!("Failed to get strategy: {}", strategy))?;
strategy
}
None => self
.select_best_strategy(input)?
.ok_or_else(|| anyhow::anyhow!("No strategy found for the given input"))?,
};

let best_strategy = get_algorithm(&input.strategy)
.ok_or_else(|| anyhow::anyhow!("No strategy found for the given input"))?;
best_strategy.route(input)
}

/// Select the best strategy based on input
fn select_best_strategy(&self, _input: &RouteInput) -> Result<Option<Box<dyn Strategy>>> {
// FIXME: we di not overdesign, would be cool to have this functionality tho
fn select_best_strategy(&self, _input: &RouteInput) -> anyhow::Result<Option<StrategyKind>> {
// TODO: Implement logic to select the best strategy based on input
// and whether the strategy can be applied to the input

// For now, we will just use the direct strategy
Ok(Some(Box::new(Direct::new())))
Ok(Some(StrategyKind::Direct))
}
}
36 changes: 30 additions & 6 deletions barq-plugin/src/methods/graph/p2p.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::Deserialize;
use serde::Serialize;

use clightningrpc_gossip_map::GossipMap;
use clightningrpc_plugin::errors::PluginError;
use clightningrpc_plugin::{error, errors::PluginError};

use barq_common::graph::{Channel, NetworkGraph, Node};

Expand Down Expand Up @@ -75,13 +75,37 @@ impl NetworkGraph for P2PNetworkGraph {
}

/// Function to build the network graph using the plugin state.
pub fn build_p2p_network_graph(
_state: &State,
_gossip_map: &GossipMap,
) -> Result<P2PNetworkGraph, PluginError> {
pub fn build_p2p_network_graph(state: &State) -> Result<P2PNetworkGraph, PluginError> {
let graph = P2PNetworkGraph::new();
// Get the gossip map path from the plugin state
// FIXME: Currently, we are loading the gossip map from the file system
// each time the `barqpay` method is called. This is not efficient.
// We should load the gossip map once and cache it in the plugin state.
// See: https://github.com/tareknaser/barq/issues/21 for more details.

// SAFETY: It is safe to unwrap here because the plugin init the path always.
let lightning_rpc_path = state.cln_rpc_path.as_ref().unwrap();
let lightning_rpc_path = std::path::Path::new(&lightning_rpc_path);
// Lightning path is /home/user/.lightning
let lightning_path = lightning_rpc_path.parent().ok_or_else(|| {
error!(
"Failed to get parent directory of CLN RPC path: {:?}",
lightning_rpc_path
)
})?;
// SAFETY: It is safe to unwrap here because the plugin init the network always.
let gossip_map_path = lightning_path
.join(state.network.as_ref().unwrap())
.join("gossip_store");
let gossip_map_path = gossip_map_path.to_str().ok_or_else(|| {
error!(
"Failed to convert gossip map path to string: {:?}",
gossip_map_path
)
})?;
let gossip_map = GossipMap::from_file(gossip_map_path)
.map_err(|err| error!("Error reading gossip map from file: {err}"))?;

// TODO: Use the gossip map to build the network graph

Ok(graph)
}
53 changes: 16 additions & 37 deletions barq-plugin/src/methods/pay.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::str::FromStr;

use serde::{Deserialize, Serialize};
use serde_json as json;

use clightningrpc_gossip_map::GossipMap;
use clightningrpc_plugin::error;
use clightningrpc_plugin::errors::PluginError;
use clightningrpc_plugin::plugin::Plugin;

use barq_common::graph::NetworkGraph;
use barq_common::strategy::{RouteInput, Router};
use barq_common::strategy::{RouteInput, Router, StrategyKind};

use crate::methods::graph::cln::build_cln_network_graph;
use crate::methods::graph::p2p::build_p2p_network_graph;
Expand Down Expand Up @@ -46,6 +47,15 @@ pub struct BarqPayRequest {
pub strategy: Option<String>,
}

impl BarqPayRequest {
pub fn strategy(&self) -> anyhow::Result<StrategyKind> {
if let Some(ref s) = self.strategy {
return StrategyKind::from_str(s);
}
Ok(StrategyKind::default())
}
}

/// Response payload for Barq pay RPC method
#[derive(Deserialize, Serialize)]
pub struct BarqPayResponse {
Expand Down Expand Up @@ -126,40 +136,9 @@ pub fn barq_pay(
// If the probabilistic strategy is selected, build the network graph from the gossip map
// else, build the network graph from the plugin state
let network_graph: Box<dyn NetworkGraph> =
if request.strategy == Some("probabilistic".to_string()) {
// Get the gossip map path from the plugin state
// FIXME: Currently, we are loading the gossip map from the file system
// each time the `barqpay` method is called. This is not efficient.
// We should load the gossip map once and cache it in the plugin state.
// See: https://github.com/tareknaser/barq/issues/21 for more details.

// This is for example: /home/user/.lightning/lightning-rpc
let lightning_rpc_path = state
.cln_rpc_path()
.ok_or_else(|| error!("CLN RPC path not found in the plugin state"))?;
let lightning_rpc_path = std::path::Path::new(&lightning_rpc_path);
// Lightning path is /home/user/.lightning
let lightning_path = lightning_rpc_path.parent().ok_or_else(|| {
error!(
"Failed to get parent directory of CLN RPC path: {:?}",
lightning_rpc_path
)
})?;
// Gossip map path is /home/user/.lightning/<network>/gossip_store
let gossip_map_path = lightning_path.join(node_network).join("gossip_store");
let gossip_map_path = gossip_map_path.to_str().ok_or_else(|| {
error!(
"Failed to convert gossip map path to string: {:?}",
gossip_map_path
)
})?;
let gossip_map = GossipMap::from_file(gossip_map_path)
.map_err(|err| error!("Error reading gossip map from file: {err}"))?;

Box::new(build_p2p_network_graph(state, &gossip_map)?)
} else {
// Build the network graph from the plugin state
Box::new(build_cln_network_graph(state)?)
match request.strategy().map_err(|e| error!("{e}"))? {
StrategyKind::Direct => Box::new(build_cln_network_graph(state)?),
StrategyKind::Probabilistic => Box::new(build_p2p_network_graph(state)?),
};

let input = RouteInput {
Expand All @@ -168,7 +147,7 @@ pub fn barq_pay(
amount_msat: b11.amount_msat,
cltv: b11.min_final_cltv_expiry,
graph: network_graph,
strategy: request.strategy,
strategy: request.strategy().map_err(|e| error!("{e}"))?,
};

// Execute the routing process
Expand Down
54 changes: 16 additions & 38 deletions barq-plugin/src/methods/route_info.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::str::FromStr;

use serde::{Deserialize, Serialize};
use serde_json as json;
use serde_json::Value;

use clightningrpc_gossip_map::GossipMap;
use clightningrpc_plugin::error;
use clightningrpc_plugin::errors::PluginError;
use clightningrpc_plugin::plugin::Plugin;

use barq_common::graph::NetworkGraph;
use barq_common::strategy::{RouteHop, RouteInput, Router};
use barq_common::strategy::{RouteHop, RouteInput, Router, StrategyKind};

use crate::methods::graph::cln::build_cln_network_graph;
use crate::methods::graph::p2p::build_p2p_network_graph;
Expand All @@ -26,6 +27,15 @@ pub struct BarqRouteInfoRequest {
pub strategy: Option<String>,
}

impl BarqRouteInfoRequest {
pub fn strategy(&self) -> anyhow::Result<StrategyKind> {
if let Some(ref s) = self.strategy {
return StrategyKind::from_str(s);
}
Ok(StrategyKind::default())
}
}

/// Response payload for Barq route info RPC method
#[derive(Deserialize, Serialize)]
pub struct BarqRouteInfoResponse {
Expand All @@ -51,49 +61,17 @@ pub fn barq_route_info(plugin: &mut Plugin<State>, request: Value) -> Result<Val
// If the probabilistic strategy is selected, build the network graph from the gossip map
// else, build the network graph from the plugin state
let network_graph: Box<dyn NetworkGraph> =
if request.strategy == Some("probabilistic".to_string()) {
// Get the gossip map path from the plugin state
// FIXME: Currently, we are loading the gossip map from the file system
// each time the `barqpay` method is called. This is not efficient.
// We should load the gossip map once and cache it in the plugin state.
// See: https://github.com/tareknaser/barq/issues/21 for more details.

// This is for example: /home/user/.lightning/lightning-rpc
let lightning_rpc_path = state
.cln_rpc_path()
.ok_or_else(|| error!("CLN RPC path not found in the plugin state"))?;
let lightning_rpc_path = std::path::Path::new(&lightning_rpc_path);
// Lightning path is /home/user/.lightning
let lightning_path = lightning_rpc_path.parent().ok_or_else(|| {
error!(
"Failed to get parent directory of CLN RPC path: {:?}",
lightning_rpc_path
)
})?;
// Gossip map path is /home/user/.lightning/<network>/gossip_store
let gossip_map_path = lightning_path.join(node_info.network).join("gossip_store");
let gossip_map_path = gossip_map_path.to_str().ok_or_else(|| {
error!(
"Failed to convert gossip map path to string: {:?}",
gossip_map_path
)
})?;
let gossip_map = GossipMap::from_file(gossip_map_path)
.map_err(|err| error!("Error reading gossip map from file: {err}"))?;

Box::new(build_p2p_network_graph(state, &gossip_map)?)
} else {
// Build the network graph from the plugin state
Box::new(build_cln_network_graph(state)?)
match request.strategy().map_err(|e| error!("{e}"))? {
StrategyKind::Direct => Box::new(build_cln_network_graph(state)?),
StrategyKind::Probabilistic => Box::new(build_p2p_network_graph(state)?),
};

let input = RouteInput {
src_pubkey: node_info.id.clone(),
dest_pubkey: request.dest_pubkey.clone(),
amount_msat: request.amount_msat,
cltv: request.cltv,
graph: network_graph,
strategy: request.strategy,
strategy: request.strategy().map_err(|e| error!("{e}"))?,
};

let output = router.execute(&input);
Expand Down
15 changes: 7 additions & 8 deletions barq-plugin/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,17 @@ pub(crate) struct State {
/// CLN RPC path
///
/// eg. /home/user/.lightning/lightning-rpc
cln_rpc_path: Option<String>,
pub(crate) cln_rpc_path: Option<String>,
pub(crate) network: Option<String>,
}

impl State {
/// Create a new Barq Plugin State
pub fn new() -> Self {
State { cln_rpc_path: None }
}

/// Get CLN RPC path
pub(crate) fn cln_rpc_path(&self) -> Option<String> {
self.cln_rpc_path.clone()
State {
cln_rpc_path: None,
network: None,
}
}

/// A convenience method to call a CLN RPC method
Expand Down Expand Up @@ -72,7 +71,7 @@ pub fn build_plugin() -> anyhow::Result<Plugin<State>> {
fn on_init(plugin: &mut Plugin<State>) -> Value {
let config = plugin.configuration.clone().unwrap();
let rpc_file = format!("{}/{}", config.lightning_dir, config.rpc_file);

plugin.state.network = Some(config.network);
plugin.state.cln_rpc_path = Some(rpc_file);

serde_json::json!({})
Expand Down
Loading

0 comments on commit b215e0b

Please sign in to comment.