From 0216178bc347def12e1029e253b446a46aa0760e Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Tue, 5 Mar 2024 12:18:52 +0100 Subject: [PATCH] Move onchain payments API to `OnchainPaymentsHandler` --- .../lightningdevkit/ldknode/AndroidLibTest.kt | 4 +- .../lightningdevkit/ldknode/LibraryTest.kt | 4 +- bindings/ldk_node.udl | 16 +++-- bindings/python/src/ldk_node/test_ldk_node.py | 4 +- src/lib.rs | 42 +++---------- src/payments/mod.rs | 2 + src/payments/onchain.rs | 63 +++++++++++++++++++ src/uniffi_types.rs | 3 +- tests/common.rs | 4 +- 9 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 src/payments/onchain.rs diff --git a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt index a5ca6eac0..fa77e387b 100644 --- a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt +++ b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt @@ -51,10 +51,10 @@ class AndroidLibTest { val nodeId2 = node2.nodeId() println("Node Id 2: $nodeId2") - val address1 = node1.newOnchainAddress() + val address1 = node1.onchain().newOnchainAddress() println("Funding address 1: $address1") - val address2 = node2.newOnchainAddress() + val address2 = node2.onchain().newOnchainAddress() println("Funding address 2: $address2") node1.stop() diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt b/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt index e3430d534..9e1a6cf49 100644 --- a/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt +++ b/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt @@ -146,10 +146,10 @@ class LibraryTest { val nodeId2 = node2.nodeId() println("Node Id 2: $nodeId2") - val address1 = node1.newOnchainAddress() + val address1 = node1.onchain().newOnchainAddress() println("Funding address 1: $address1") - val address2 = node2.newOnchainAddress() + val address2 = node2.onchain().newOnchainAddress() println("Funding address 2: $address2") val txid1 = sendToAddress(address1, 100000u) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index caab7d111..3312fc4a4 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -53,12 +53,7 @@ interface Node { sequence? listening_addresses(); Bolt11PaymentsHandler bolt11(); SpontaneousPaymentsHandler spontaneous(); - [Throws=NodeError] - Address new_onchain_address(); - [Throws=NodeError] - Txid send_to_onchain_address([ByRef]Address address, u64 amount_msat); - [Throws=NodeError] - Txid send_all_to_onchain_address([ByRef]Address address); + OnchainPaymentsHandler onchain(); [Throws=NodeError] void connect(PublicKey node_id, SocketAddress address, boolean persist); [Throws=NodeError] @@ -110,6 +105,15 @@ interface SpontaneousPaymentsHandler { void send_spontaneous_payment_probes(u64 amount_msat, PublicKey node_id); }; +interface OnchainPaymentsHandler { + [Throws=NodeError] + Address new_onchain_address(); + [Throws=NodeError] + Txid send_to_onchain_address([ByRef]Address address, u64 amount_msat); + [Throws=NodeError] + Txid send_all_to_onchain_address([ByRef]Address address); +}; + [Error] enum NodeError { "AlreadyRunning", diff --git a/bindings/python/src/ldk_node/test_ldk_node.py b/bindings/python/src/ldk_node/test_ldk_node.py index 436f39ef2..1edccf50b 100644 --- a/bindings/python/src/ldk_node/test_ldk_node.py +++ b/bindings/python/src/ldk_node/test_ldk_node.py @@ -125,9 +125,9 @@ def test_channel_full_cycle(self): node_id_2 = node_2.node_id() print("Node ID 2:", node_id_2) - address_1 = node_1.new_onchain_address() + address_1 = node_1.onchain().new_onchain_address() txid_1 = send_to_address(address_1, 100000) - address_2 = node_2.new_onchain_address() + address_2 = node_2.onchain().new_onchain_address() txid_2 = send_to_address(address_2, 100000) wait_for_tx(esplora_endpoint, txid_1) diff --git a/src/lib.rs b/src/lib.rs index 461f74093..4d8de8b7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ use gossip::GossipSource; use liquidity::LiquiditySource; use payment_store::PaymentStore; pub use payment_store::{LSPFeeLimits, PaymentDetails, PaymentDirection, PaymentStatus}; -use payments::{Bolt11PaymentsHandler, SpontaneousPaymentsHandler}; +use payments::{Bolt11PaymentsHandler, OnchainPaymentsHandler, SpontaneousPaymentsHandler}; use peer_store::{PeerInfo, PeerStore}; use types::{ Broadcaster, ChainMonitor, ChannelManager, DynStore, FeeEstimator, KeysManager, NetworkGraph, @@ -154,7 +154,6 @@ use lightning_background_processor::process_events_async; use lightning_transaction_sync::EsploraSyncClient; use bitcoin::secp256k1::PublicKey; -use bitcoin::{Address, Txid}; use rand::Rng; @@ -771,38 +770,13 @@ impl Node { )) } - /// Retrieve a new on-chain/funding address. - pub fn new_onchain_address(&self) -> Result { - let funding_address = self.wallet.get_new_address()?; - log_info!(self.logger, "Generated new funding address: {}", funding_address); - Ok(funding_address) - } - - /// Send an on-chain payment to the given address. - pub fn send_to_onchain_address( - &self, address: &bitcoin::Address, amount_sats: u64, - ) -> Result { - let rt_lock = self.runtime.read().unwrap(); - if rt_lock.is_none() { - return Err(Error::NotRunning); - } - - let cur_balance = self.wallet.get_balance()?; - if cur_balance.get_spendable() < amount_sats { - log_error!(self.logger, "Unable to send payment due to insufficient funds."); - return Err(Error::InsufficientFunds); - } - self.wallet.send_to_address(address, Some(amount_sats)) - } - - /// Send an on-chain payment to the given address, draining all the available funds. - pub fn send_all_to_onchain_address(&self, address: &bitcoin::Address) -> Result { - let rt_lock = self.runtime.read().unwrap(); - if rt_lock.is_none() { - return Err(Error::NotRunning); - } - - self.wallet.send_to_address(address, None) + /// Returns a payment handler allowing to send and receive on-chain payments. + pub fn onchain(&self) -> Arc { + Arc::new(OnchainPaymentsHandler::new( + Arc::clone(&self.runtime), + Arc::clone(&self.wallet), + Arc::clone(&self.logger), + )) } /// Retrieve a list of known channels. diff --git a/src/payments/mod.rs b/src/payments/mod.rs index 8821d7cc5..bc56ccf04 100644 --- a/src/payments/mod.rs +++ b/src/payments/mod.rs @@ -1,7 +1,9 @@ //! Handlers for different types of payments. mod bolt11; +mod onchain; mod spontaneous; pub use bolt11::Bolt11PaymentsHandler; +pub use onchain::OnchainPaymentsHandler; pub use spontaneous::SpontaneousPaymentsHandler; diff --git a/src/payments/onchain.rs b/src/payments/onchain.rs new file mode 100644 index 000000000..c315d9cba --- /dev/null +++ b/src/payments/onchain.rs @@ -0,0 +1,63 @@ +//! Holds a payment handler allowing to send and receive on-chain payments. + +use crate::error::Error; +use crate::logger::{log_error, log_info, FilesystemLogger, Logger}; +use crate::types::Wallet; + +use bitcoin::{Address, Txid}; + +use std::sync::{Arc, RwLock}; + +/// A payment handler allowing to send and receive on-chain payments. +/// +/// Should be retrieved by calling [`Node::onchain`]. +/// +/// [`Node::onchain`]: crate::Node::onchain +pub struct OnchainPaymentsHandler { + runtime: Arc>>, + wallet: Arc, + logger: Arc, +} + +impl OnchainPaymentsHandler { + pub(crate) fn new( + runtime: Arc>>, wallet: Arc, + logger: Arc, + ) -> Self { + Self { runtime, wallet, logger } + } + + /// Retrieve a new on-chain/funding address. + pub fn new_onchain_address(&self) -> Result { + let funding_address = self.wallet.get_new_address()?; + log_info!(self.logger, "Generated new funding address: {}", funding_address); + Ok(funding_address) + } + + /// Send an on-chain payment to the given address. + pub fn send_to_onchain_address( + &self, address: &bitcoin::Address, amount_sats: u64, + ) -> Result { + let rt_lock = self.runtime.read().unwrap(); + if rt_lock.is_none() { + return Err(Error::NotRunning); + } + + let cur_balance = self.wallet.get_balance()?; + if cur_balance.get_spendable() < amount_sats { + log_error!(self.logger, "Unable to send payment due to insufficient funds."); + return Err(Error::InsufficientFunds); + } + self.wallet.send_to_address(address, Some(amount_sats)) + } + + /// Send an on-chain payment to the given address, draining all the available funds. + pub fn send_all_to_onchain_address(&self, address: &bitcoin::Address) -> Result { + let rt_lock = self.runtime.read().unwrap(); + if rt_lock.is_none() { + return Err(Error::NotRunning); + } + + self.wallet.send_to_address(address, None) + } +} diff --git a/src/uniffi_types.rs b/src/uniffi_types.rs index 0cef466a1..7204f67f1 100644 --- a/src/uniffi_types.rs +++ b/src/uniffi_types.rs @@ -4,7 +4,7 @@ pub use lightning::util::string::UntrustedString; pub use lightning_invoice::Bolt11Invoice; -pub use bitcoin::{BlockHash, Network, OutPoint}; +pub use bitcoin::{Address, BlockHash, Network, OutPoint, Txid}; pub use bip39::Mnemonic; @@ -17,7 +17,6 @@ use crate::{SocketAddress, UserChannelId}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use bitcoin::secp256k1::PublicKey; -use bitcoin::{Address, Txid}; use lightning_invoice::SignedRawBolt11Invoice; use std::convert::TryInto; diff --git a/tests/common.rs b/tests/common.rs index cf808fd55..981087f7e 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -317,8 +317,8 @@ pub fn open_channel( pub(crate) fn do_channel_full_cycle( node_a: TestNode, node_b: TestNode, bitcoind: &BitcoindClient, electrsd: &E, allow_0conf: bool, ) { - let addr_a = node_a.new_onchain_address().unwrap(); - let addr_b = node_b.new_onchain_address().unwrap(); + let addr_a = node_a.onchain().new_onchain_address().unwrap(); + let addr_b = node_b.onchain().new_onchain_address().unwrap(); let premine_amount_sat = 100_000;