-
Notifications
You must be signed in to change notification settings - Fork 13
Implement first set of Api's #5
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
Changes from all commits
0485c7a
f57637d
ba60e59
d4295c8
70fb33d
41eaa1b
ac90b8f
e63d1ae
92d3361
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use ldk_node::Node; | ||
use protos::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; | ||
|
||
pub(crate) fn handle_bolt11_receive_request( | ||
node: Arc<Node>, request: Bolt11ReceiveRequest, | ||
) -> Result<Bolt11ReceiveResponse, ldk_node::NodeError> { | ||
let invoice = match request.amount_msat { | ||
Some(amount_msat) => { | ||
node.bolt11_payment().receive(amount_msat, &request.description, request.expiry_secs)? | ||
}, | ||
None => node | ||
.bolt11_payment() | ||
.receive_variable_amount(&request.description, request.expiry_secs)?, | ||
}; | ||
|
||
let response = Bolt11ReceiveResponse { invoice: invoice.to_string() }; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use bytes::Bytes; | ||
use ldk_node::lightning_invoice::Bolt11Invoice; | ||
use ldk_node::Node; | ||
use protos::{Bolt11SendRequest, Bolt11SendResponse}; | ||
use std::str::FromStr; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const BOLT11_SEND_PATH: &str = "Bolt11Send"; | ||
|
||
pub(crate) fn handle_bolt11_send_request( | ||
node: Arc<Node>, request: Bolt11SendRequest, | ||
) -> Result<Bolt11SendResponse, ldk_node::NodeError> { | ||
let invoice = Bolt11Invoice::from_str(&request.invoice.as_str()) | ||
.map_err(|_| ldk_node::NodeError::InvalidInvoice)?; | ||
|
||
let payment_id = match request.amount_msat { | ||
None => node.bolt11_payment().send(&invoice), | ||
Some(amount_msat) => node.bolt11_payment().send_using_amount(&invoice, amount_msat), | ||
}?; | ||
|
||
let response = Bolt11SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
use ldk_node::Node; | ||
use protos::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; | ||
|
||
pub(crate) fn handle_bolt12_receive_request( | ||
node: Arc<Node>, request: Bolt12ReceiveRequest, | ||
) -> Result<Bolt12ReceiveResponse, ldk_node::NodeError> { | ||
let offer = match request.amount_msat { | ||
Some(amount_msat) => node.bolt12_payment().receive(amount_msat, &request.description)?, | ||
None => node.bolt12_payment().receive_variable_amount(&request.description)?, | ||
}; | ||
|
||
let response = Bolt12ReceiveResponse { offer: offer.to_string() }; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use bytes::Bytes; | ||
use ldk_node::lightning::offers::offer::Offer; | ||
use ldk_node::Node; | ||
use protos::{Bolt12SendRequest, Bolt12SendResponse}; | ||
use std::str::FromStr; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const BOLT12_SEND_PATH: &str = "Bolt12Send"; | ||
|
||
pub(crate) fn handle_bolt12_send_request( | ||
node: Arc<Node>, request: Bolt12SendRequest, | ||
) -> Result<Bolt12SendResponse, ldk_node::NodeError> { | ||
let offer = | ||
Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; | ||
|
||
let payment_id = match request.amount_msat { | ||
None => node.bolt12_payment().send(&offer, request.payer_note), | ||
Some(amount_msat) => { | ||
node.bolt12_payment().send_using_amount(&offer, request.payer_note, amount_msat) | ||
}, | ||
}?; | ||
|
||
let response = Bolt12SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use ldk_node::bitcoin::secp256k1::PublicKey; | ||
use ldk_node::{Node, UserChannelId}; | ||
use protos::{CloseChannelRequest, CloseChannelResponse}; | ||
use std::str::FromStr; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; | ||
|
||
pub(crate) fn handle_close_channel_request( | ||
node: Arc<Node>, request: CloseChannelRequest, | ||
) -> Result<CloseChannelResponse, ldk_node::NodeError> { | ||
//TODO: Should this be string? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tnull @jkczyz Using bytes is fine for programmatic access, but for CLI or while interacting with a lightning node through a UI, this isn't really feasible. We have a similar problem for the logs of these IDs as well. (See: lightningdevkit/rust-lightning#3306) In my opinion, we need a standardized way of interacting with these in a human-friendly manner, not just for debug logs. For this, I was considering whether we can use a hex representation string in the interface. This could be just for the CLI/UI or as part of the main API interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mhh, I don't have a strong opinion, but I do think it should be uniform, at least across all There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought more about this,
So to make it uniform, I am thinking of removing PaymentId type itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Alright, fine by me as long as it's uniform and ~predictable by the user/dev so they don't have to look up every single detail in the docs when using the API. And, at this stage, we could still easily change anything if we find a reason why we need separate types in the future. Feel free to add the commit dropping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes added a commit for it. |
||
let mut user_channel_id_bytes = [0u8; 16]; | ||
user_channel_id_bytes.copy_from_slice(&request.user_channel_id); | ||
let user_channel_id = UserChannelId(u128::from_be_bytes(user_channel_id_bytes)); | ||
let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) | ||
.map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; | ||
|
||
match request.force_close { | ||
Some(true) => node.force_close_channel(&user_channel_id, counterparty_node_id)?, | ||
_ => node.close_channel(&user_channel_id, counterparty_node_id)?, | ||
}; | ||
|
||
let response = CloseChannelResponse {}; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pub(crate) mod bolt11_receive; | ||
pub(crate) mod bolt11_send; | ||
pub(crate) mod bolt12_receive; | ||
pub(crate) mod bolt12_send; | ||
pub(crate) mod close_channel; | ||
pub(crate) mod onchain_receive; | ||
pub(crate) mod onchain_send; | ||
pub(crate) mod open_channel; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
use ldk_node::Node; | ||
use protos::{OnchainReceiveRequest, OnchainReceiveResponse}; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mh, fine by me that we dropped the actual There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wanted to avoid another mapping from api to api path, hence used it as it is. (i.e. /OnchainReceive for OnchainReceiveRequest and OnchainReceiveResponse.) |
||
pub(crate) fn handle_onchain_receive_request( | ||
node: Arc<Node>, _request: OnchainReceiveRequest, | ||
) -> Result<OnchainReceiveResponse, ldk_node::NodeError> { | ||
let response = | ||
OnchainReceiveResponse { address: node.onchain_payment().new_address()?.to_string() }; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use ldk_node::bitcoin::Address; | ||
use ldk_node::Node; | ||
use protos::{OnchainSendRequest, OnchainSendResponse}; | ||
use std::str::FromStr; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const ONCHAIN_SEND_PATH: &str = "OnchainSend"; | ||
|
||
pub(crate) fn handle_onchain_send_request( | ||
node: Arc<Node>, request: OnchainSendRequest, | ||
) -> Result<OnchainSendResponse, ldk_node::NodeError> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be fine for the intial step, but we might need to introduce a separate error type that wraps the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah currently it is only for initial step, will probably spend more time on error handling when we have it in api interface. |
||
let address = Address::from_str(&request.address) | ||
.map_err(|_| ldk_node::NodeError::InvalidAddress)? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we import There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept it to make it explicit when there are other error types floating around, specifically ldk-server specific. |
||
.require_network(node.config().network) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it would be worth retrieving the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not all api's need it, and there could be future such instances where a subset of api's need some field. |
||
.map_err(|_| ldk_node::NodeError::InvalidAddress)?; | ||
tnull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let txid = match (request.amount_sats, request.send_all) { | ||
(Some(amount_sats), None) => { | ||
node.onchain_payment().send_to_address(&address, amount_sats)? | ||
}, | ||
(None, Some(true)) => node.onchain_payment().send_all_to_address(&address)?, | ||
_ => return Err(ldk_node::NodeError::InvalidAmount), | ||
}; | ||
let response = OnchainSendResponse { txid: txid.to_string() }; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use bytes::Bytes; | ||
use ldk_node::bitcoin::secp256k1::PublicKey; | ||
use ldk_node::lightning::ln::msgs::SocketAddress; | ||
use ldk_node::Node; | ||
use protos::{OpenChannelRequest, OpenChannelResponse}; | ||
use std::str::FromStr; | ||
use std::sync::Arc; | ||
|
||
pub(crate) const OPEN_CHANNEL_PATH: &str = "OpenChannel"; | ||
|
||
pub(crate) fn handle_open_channel( | ||
node: Arc<Node>, request: OpenChannelRequest, | ||
) -> Result<OpenChannelResponse, ldk_node::NodeError> { | ||
let node_id = PublicKey::from_str(&request.node_pubkey) | ||
.map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; | ||
let address = SocketAddress::from_str(&request.address) | ||
.map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; | ||
let user_channel_id = node.connect_open_channel( | ||
node_id, | ||
address, | ||
request.channel_amount_sats, | ||
request.push_to_counterparty_msat, | ||
// TODO: Allow setting ChannelConfig in open-channel. | ||
None, | ||
G8XSU marked this conversation as resolved.
Show resolved
Hide resolved
|
||
request.announce_channel, | ||
)?; | ||
let response = OpenChannelResponse { | ||
user_channel_id: Bytes::from(user_channel_id.0.to_be_bytes().to_vec()), | ||
}; | ||
Ok(response) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod api; | ||
mod service; | ||
|
||
use crate::service::NodeService; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,23 @@ use std::future::Future; | |
use std::pin::Pin; | ||
use std::sync::Arc; | ||
|
||
use crate::api::bolt11_receive::handle_bolt11_receive_request; | ||
use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Could group the imports from each module, but doesn't matter too much. |
||
use crate::api::bolt11_send::handle_bolt11_send_request; | ||
use crate::api::bolt11_send::BOLT11_SEND_PATH; | ||
use crate::api::bolt12_receive::handle_bolt12_receive_request; | ||
use crate::api::bolt12_receive::BOLT12_RECEIVE_PATH; | ||
use crate::api::bolt12_send::handle_bolt12_send_request; | ||
use crate::api::bolt12_send::BOLT12_SEND_PATH; | ||
use crate::api::close_channel::handle_close_channel_request; | ||
use crate::api::close_channel::CLOSE_CHANNEL_PATH; | ||
use crate::api::onchain_receive::handle_onchain_receive_request; | ||
use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; | ||
use crate::api::onchain_send::handle_onchain_send_request; | ||
use crate::api::onchain_send::ONCHAIN_SEND_PATH; | ||
use crate::api::open_channel::handle_open_channel; | ||
use crate::api::open_channel::OPEN_CHANNEL_PATH; | ||
|
||
#[derive(Clone)] | ||
pub struct NodeService { | ||
node: Arc<Node>, | ||
|
@@ -28,8 +45,22 @@ impl Service<Request<Incoming>> for NodeService { | |
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; | ||
|
||
fn call(&self, req: Request<Incoming>) -> Self::Future { | ||
let _node = Arc::clone(&self.node); | ||
let node = Arc::clone(&self.node); | ||
match req.uri().path() { | ||
ONCHAIN_RECEIVE_PATH => { | ||
Box::pin(handle_request(node, req, handle_onchain_receive_request)) | ||
}, | ||
ONCHAIN_SEND_PATH => Box::pin(handle_request(node, req, handle_onchain_send_request)), | ||
BOLT11_RECEIVE_PATH => { | ||
Box::pin(handle_request(node, req, handle_bolt11_receive_request)) | ||
}, | ||
BOLT11_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt11_send_request)), | ||
BOLT12_RECEIVE_PATH => { | ||
Box::pin(handle_request(node, req, handle_bolt12_receive_request)) | ||
}, | ||
BOLT12_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt12_send_request)), | ||
OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), | ||
CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), | ||
path => { | ||
let error = format!("Unknown request: {}", path).into_bytes(); | ||
Box::pin(async { | ||
|
Uh oh!
There was an error while loading. Please reload this page.