breez_sdk_core/
node_api.rs

1use std::collections::HashSet;
2use std::pin::Pin;
3
4use anyhow::Result;
5use serde_json::Value;
6use tokio::sync::{mpsc, watch};
7use tokio_stream::Stream;
8use tonic::Streaming;
9
10use sdk_common::prelude::*;
11
12use crate::{
13    bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey},
14    lightning_invoice::RawBolt11Invoice,
15    persist::error::PersistError,
16    CustomMessage, LnUrlAuthError, LspInformation, MaxChannelAmount, NodeCredentials, Payment,
17    PaymentResponse, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse,
18    RouteHint, RouteHintHop, SyncResponse, TlvEntry,
19};
20
21pub type NodeResult<T, E = NodeError> = Result<T, E>;
22
23#[derive(Debug, thiserror::Error)]
24pub enum NodeError {
25    #[error("{0}")]
26    Credentials(String),
27
28    #[error("{0}")]
29    Generic(String),
30
31    #[error(transparent)]
32    InvalidInvoice(#[from] InvoiceError),
33
34    #[error("{0}")]
35    InvoiceExpired(String),
36
37    #[error("{0}")]
38    InvoiceNoDescription(String),
39
40    #[error("{0}")]
41    InvoicePreimageAlreadyExists(String),
42
43    #[error("{0}")]
44    PaymentFailed(String),
45
46    #[error("{0}")]
47    PaymentTimeout(String),
48
49    #[error(transparent)]
50    Persistance(#[from] PersistError),
51
52    #[error("{0}")]
53    RestoreOnly(String),
54
55    #[error("{0}")]
56    RouteTooExpensive(String),
57
58    #[error("{0}")]
59    RouteNotFound(String),
60
61    #[error("{0}")]
62    ServiceConnectivity(String),
63
64    #[error("{0}")]
65    InsufficientFunds(String),
66
67    #[error("invoice already paid")]
68    InvoiceAlreadyPaid,
69}
70
71impl NodeError {
72    pub(crate) fn credentials(err: &str) -> Self {
73        Self::Credentials(err.to_string())
74    }
75
76    pub(crate) fn generic(err: &str) -> Self {
77        Self::Generic(err.to_string())
78    }
79}
80
81impl From<NodeError> for sdk_common::prelude::LnUrlError {
82    fn from(value: NodeError) -> Self {
83        match value {
84            NodeError::InvalidInvoice(err) => Self::InvalidInvoice(format!("{err}")),
85            NodeError::ServiceConnectivity(err) => Self::ServiceConnectivity(err),
86            _ => Self::Generic(value.to_string()),
87        }
88    }
89}
90
91impl From<NodeError> for LnUrlAuthError {
92    fn from(value: NodeError) -> Self {
93        match value {
94            NodeError::ServiceConnectivity(err) => Self::ServiceConnectivity { err },
95            _ => Self::Generic {
96                err: value.to_string(),
97            },
98        }
99    }
100}
101
102pub struct CreateInvoiceRequest {
103    pub amount_msat: u64,
104    pub description: String,
105    pub payer_amount_msat: Option<u64>,
106    pub preimage: Option<Vec<u8>>,
107    pub use_description_hash: Option<bool>,
108    pub expiry: Option<u32>,
109    pub cltv: Option<u32>,
110}
111
112pub struct FetchBolt11Result {
113    pub bolt11: String,
114    pub payer_amount_msat: Option<u64>,
115}
116
117/// Trait covering functions affecting the LN node
118#[cfg_attr(test, mockall::automock)]
119#[tonic::async_trait]
120pub trait NodeAPI: Send + Sync {
121    async fn node_credentials(&self) -> NodeResult<Option<NodeCredentials>>;
122    async fn configure_node(&self, close_to_address: Option<String>) -> NodeResult<()>;
123    async fn create_invoice(&self, request: CreateInvoiceRequest) -> NodeResult<String>;
124    async fn delete_invoice(&self, bolt11: String) -> NodeResult<()>;
125    /// Fetches an existing BOLT11 invoice from the node
126    async fn fetch_bolt11(&self, payment_hash: Vec<u8>) -> NodeResult<Option<FetchBolt11Result>>;
127    async fn pull_changed(
128        &self,
129        sync_state: Option<Value>,
130        match_local_balance: bool,
131    ) -> NodeResult<SyncResponse>;
132    /// As per the `pb::PayRequest` docs, `amount_msat` is only needed when the invoice doesn't specify an amount
133    async fn send_payment(
134        &self,
135        bolt11: String,
136        amount_msat: Option<u64>,
137        label: Option<String>,
138    ) -> NodeResult<Payment>;
139    async fn send_spontaneous_payment(
140        &self,
141        node_id: String,
142        amount_msat: u64,
143        extra_tlvs: Option<Vec<TlvEntry>>,
144        label: Option<String>,
145    ) -> NodeResult<Payment>;
146    async fn send_trampoline_payment(
147        &self,
148        bolt11: String,
149        amount_msat: u64,
150        label: Option<String>,
151        trampoline_node_id: Vec<u8>,
152    ) -> NodeResult<Payment>;
153    async fn node_id(&self) -> NodeResult<String>;
154
155    /// Attempts to find a payment path "manually" and send the htlcs in a way that will drain
156    /// Large channels first.
157    /// This is useful function to send the largest amount possible to a node.
158    async fn send_pay(&self, bolt11: String, max_hops: u32) -> NodeResult<PaymentResponse>;
159
160    /// Calculates the maximum amount that can be sent to a node.
161    async fn max_sendable_amount<'a>(
162        &self,
163        payee_node_id: Option<Vec<u8>>,
164        max_hops: u32,
165        last_hop: Option<&'a RouteHintHop>,
166    ) -> NodeResult<Vec<MaxChannelAmount>>;
167    async fn redeem_onchain_funds(
168        &self,
169        to_address: String,
170        sat_per_vbyte: u32,
171    ) -> NodeResult<Vec<u8>>;
172    async fn prepare_redeem_onchain_funds(
173        &self,
174        req: PrepareRedeemOnchainFundsRequest,
175    ) -> NodeResult<PrepareRedeemOnchainFundsResponse>;
176    async fn start_signer(&self, shutdown: mpsc::Receiver<()>);
177    async fn start_keep_alive(&self, shutdown: watch::Receiver<()>);
178    async fn connect_peer(&self, node_id: String, addr: String) -> NodeResult<()>;
179    async fn sign_invoice(&self, invoice: RawBolt11Invoice) -> NodeResult<String>;
180    async fn close_peer_channels(&self, node_id: String) -> NodeResult<Vec<String>>;
181    async fn stream_incoming_payments(
182        &self,
183    ) -> NodeResult<Streaming<gl_client::signer::model::greenlight::IncomingPayment>>;
184    async fn stream_log_messages(
185        &self,
186    ) -> NodeResult<Streaming<gl_client::signer::model::greenlight::LogEntry>>;
187    async fn static_backup(&self) -> NodeResult<Vec<String>>;
188    async fn execute_command(&self, command: String) -> NodeResult<Value>;
189    async fn generate_diagnostic_data(&self) -> NodeResult<Value>;
190    async fn sign_message(&self, message: &str) -> NodeResult<String>;
191    async fn check_message(&self, message: &str, pubkey: &str, signature: &str)
192        -> NodeResult<bool>;
193    async fn send_custom_message(&self, message: CustomMessage) -> NodeResult<()>;
194    async fn stream_custom_messages(
195        &self,
196    ) -> NodeResult<Pin<Box<dyn Stream<Item = Result<CustomMessage>> + Send>>>;
197
198    /// Gets the private key at the path specified
199    async fn derive_bip32_key(&self, path: Vec<ChildNumber>) -> NodeResult<ExtendedPrivKey>;
200    async fn legacy_derive_bip32_key(&self, path: Vec<ChildNumber>) -> NodeResult<ExtendedPrivKey>;
201
202    /// Gets the routing hints related to all private channels that the node has.
203    /// Also returns a boolean indicating if the node has a public channel or not.
204    async fn get_routing_hints(
205        &self,
206        lsp_info: &LspInformation,
207    ) -> NodeResult<(Vec<RouteHint>, bool)>;
208    /// Get peers with whom we have an open channel
209    async fn get_open_peers(&self) -> NodeResult<HashSet<Vec<u8>>>;
210}