Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(common): fix the direct payment #44

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 30 additions & 14 deletions barq-common/src/algorithms/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use anyhow::Result;

use crate::strategy::{RouteHop, RouteInput, RouteOutput, Strategy};

const DEFAULT_DELAY: u32 = 9;

/// A routing strategy that attempts to find a direct route from the source to
/// the destination.
///
Expand Down Expand Up @@ -61,20 +59,38 @@ impl Strategy for Direct {
.get_node(&source)
.ok_or_else(|| anyhow::anyhow!("Failed to retrieve node from graph"))?;

let mut path: Vec<RouteHop> = Vec::<RouteHop>::new();
let channels = node
.channels
.iter()
.filter(|ch| ch.node1 == input.dest_pubkey || ch.node2 == input.dest_pubkey)
.collect::<Vec<_>>();

for edge in &node.channels {
if input.dest_pubkey == edge.node1.clone() || input.dest_pubkey == edge.node2.clone() {
let hop = RouteHop::new(
input.dest_pubkey.clone(),
edge.id.clone(),
DEFAULT_DELAY,
input.amount_msat,
);
path.push(hop);
}
if channels.is_empty() {
anyhow::bail!("No channel with `{}` found", input.dest_pubkey);
}

Ok(RouteOutput { path })
let channels = channels
.iter()
.filter(|c| c.capacity >= input.amount_msat)
.collect::<Vec<_>>();
let Some(channel) = channels.first() else {
anyhow::bail!(
"No channel with capacity `{}` with peer `{}` found",
input.amount_msat,
input.dest_pubkey
);
};

let hop = RouteHop::new(
input.dest_pubkey.clone(),
channel.short_channel_id.clone(),
input.cltv as u32,
// FIXME: Double check for this?
input.amount_msat
+ channel.base_fee_millisatoshi
+ (channel.fee_per_millionth * input.amount_msat),
);

Ok(RouteOutput { path: vec![hop] })
}
}
4 changes: 2 additions & 2 deletions barq-common/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Node {
/// Represents a channel between two nodes in the network graph.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Channel {
pub id: String,
pub short_channel_id: String,
pub node1: String,
pub node2: String,
pub capacity: u64,
Expand All @@ -59,7 +59,7 @@ impl Channel {
fee_per_millionth: u64,
) -> Self {
Channel {
id: id.to_string(),
short_channel_id: id.to_string(),
node1: node1.to_string(),
node2: node2.to_string(),
capacity,
Expand Down
2 changes: 1 addition & 1 deletion barq-plugin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ anyhow = { workspace = true }
# Core lightning-rpc dependencies
clightningrpc = { git = "https://github.com/laanwj/cln4rust.git" }
clightningrpc-common = { git = "https://github.com/laanwj/cln4rust.git" }
clightningrpc-plugin = { git = "https://github.com/laanwj/cln4rust.git" }
clightningrpc-plugin = { git = "https://github.com/laanwj/cln4rust.git", features = ["log"] }
clightningrpc-plugin-macros = { git = "https://github.com/laanwj/cln4rust.git" }
clightningrpc_gossip_map = { version = "0.0.1-beta.4" }

Expand Down
11 changes: 3 additions & 8 deletions barq-plugin/src/methods/graph/cln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use clightningrpc_plugin::error;
use clightningrpc_plugin::errors::PluginError;

use barq_common::graph::{Channel, NetworkGraph, Node};
Expand Down Expand Up @@ -38,7 +37,8 @@ impl CLNNetworkGraph {

/// Adds a channel to the network graph.
pub fn add_channel(&mut self, channel: Channel) {
self.channels.insert(channel.id.clone(), channel.clone());
self.channels
.insert(channel.short_channel_id.clone(), channel.clone());
self.nodes
.get_mut(&channel.node1)
.unwrap()
Expand Down Expand Up @@ -93,17 +93,12 @@ pub fn build_cln_network_graph(state: &State) -> Result<CLNNetworkGraph, PluginE
// Call the `listchannels` method to get the network information
let response: CLNListChannelsResponse = state
.call("listchannels", serde_json::json!({}))
.map_err(|err| error!("Error calling `listchannels`: {err}"))?;
.map_err(|err| PluginError::new(err.code, &err.message, err.data))?;

let mut graph = CLNNetworkGraph::new();

// Iterate over the channels to construct the nodes and edges
for channel in response.channels {
// Add nodes to the graph
if graph.get_node(&channel.source).is_none() {
graph.add_node(Node::new(&channel.source));
}

// Convert amount_msat to u64
let amount_msat = channel.amount_msat;

Expand Down
3 changes: 2 additions & 1 deletion barq-plugin/src/methods/graph/p2p.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ impl P2PNetworkGraph {

/// Adds a channel to the network graph.
pub fn add_channel(&mut self, channel: Channel) {
self.channels.insert(channel.id.clone(), channel.clone());
self.channels
.insert(channel.short_channel_id.clone(), channel.clone());
self.nodes
.get_mut(&channel.node1)
.unwrap_or(&mut Node::new(&channel.node1))
Expand Down
17 changes: 10 additions & 7 deletions barq-plugin/src/methods/pay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct Bolt11 {
amount_msat: Option<u64>,
payment_hash: String,
min_final_cltv_expiry: u64,
payment_secret: String, // FIXME: Should this be optional?
payment_secret: Option<String>,
}

/// Response from `getinfo` RPC command of Core Lightning
Expand Down Expand Up @@ -120,7 +120,7 @@ pub fn barq_pay(
"bolt11": request.bolt11_invoice
}),
)
.map_err(|err| error!("Error calling CLN RPC method: {err}"))?;
.map_err(|err| PluginError::new(err.code, &err.message, err.data))?;

// Get the network of the invoice
// See: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md#human-readable-part
Expand All @@ -134,7 +134,7 @@ pub fn barq_pay(

let node_info: NodeInfo = state
.call("getinfo", serde_json::json!({}))
.map_err(|err| error!("Error calling CLN RPC method: {err}"))?;
.map_err(|err| PluginError::new(err.code, &err.message, err.data))?;

let amount = match (b11.amount_msat, request.amount_msat) {
(Some(_), Some(_)) => {
Expand Down Expand Up @@ -180,23 +180,26 @@ pub fn barq_pay(
if output.path.is_empty() {
return Err(error!("No route found between us and `{}`", b11.payee));
}
log::info!("path selected by the strategy is: `{:?}`", output.path);
let sendpay_request: json::Value = serde_json::json!({
"route": output.path,
"payment_hash": b11.payment_hash,
"payment_secret": b11.payment_secret
"payment_secret": b11.payment_secret,
"partid": 0,
});

let sendpay_response: CLNSendpayResponse = state
.call("sendpay", sendpay_request)
.map_err(|err| error!("Error calling sendpay method: {err}"))?;
.map_err(|err| PluginError::new(err.code, &err.message, err.data))?;

let waitsendpay_request: json::Value = serde_json::json!({
"payment_hash": sendpay_response.payment_hash.clone()
"payment_hash": sendpay_response.payment_hash.clone(),
"partid": 0,
});

let waitsendpay_response: CLNSendpayResponse = state
.call("waitsendpay", waitsendpay_request)
.map_err(|err| error!("Error calling waitsendpay method: {err}"))?;
.map_err(|err| PluginError::new(err.code, &err.message, err.data))?;

// Construct the response from the output
BarqPayResponse {
Expand Down
29 changes: 22 additions & 7 deletions barq-plugin/src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Barq Plugin implementation

use clightningrpc_common::errors::{Error, RpcError};
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::Value;
Expand Down Expand Up @@ -39,15 +40,29 @@ impl State {
&self,
method: &str,
payload: T,
) -> anyhow::Result<U> {
let path = self
.cln_rpc_path
.as_ref()
.ok_or(anyhow::anyhow!("cln socket path not found"))?;
) -> Result<U, RpcError> {
let path = self.cln_rpc_path.as_ref().ok_or(RpcError {
code: -1,
message: "CLN RPC path is unset".to_owned(),
data: None,
})?;
let rpc = LightningRPC::new(path);
let response: U = rpc.call(method, payload)?;
let response = rpc.call::<T, U>(method, payload);
log::debug!("cln response: {:?}", response);
Ok(response)
// We need to clean up the errors inside the library a bit
match response {
Ok(response) => Ok(response),
Err(clightningrpc::Error::Rpc(err)) => Err(RpcError {
code: err.code,
message: err.message,
data: err.data,
}),
Err(err) => Err(RpcError {
code: -1,
message: format!("{err}"),
data: None,
}),
}
}
}

Expand Down