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