From e158634a2f9b6691029434d187f014bfcccc2b10 Mon Sep 17 00:00:00 2001 From: Sergi Delgado Segura Date: Fri, 7 Jul 2023 15:30:40 -0400 Subject: [PATCH] WIP: testing https://github.com/lightningdevkit/rust-lightning/pull/2337 --- Cargo.lock | 14 ++--- Cargo.toml | 14 ++--- src/main.rs | 14 +++-- src/sweep.rs | 5 +- src/tower.rs | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 23 deletions(-) create mode 100644 src/tower.rs diff --git a/Cargo.lock b/Cargo.lock index 21e8307b..6f2ca5cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -258,7 +258,7 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "lightning" version = "0.0.116-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bitcoin", "musig2", @@ -267,7 +267,7 @@ dependencies = [ [[package]] name = "lightning-background-processor" version = "0.0.116-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bitcoin", "lightning", @@ -277,7 +277,7 @@ dependencies = [ [[package]] name = "lightning-block-sync" version = "0.0.116-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bitcoin", "chunked_transfer", @@ -288,7 +288,7 @@ dependencies = [ [[package]] name = "lightning-invoice" version = "0.24.0-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bech32 0.9.1", "bitcoin", @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "lightning-net-tokio" version = "0.0.116-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bitcoin", "lightning", @@ -311,7 +311,7 @@ dependencies = [ [[package]] name = "lightning-persister" version = "0.0.116-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bitcoin", "libc", @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "lightning-rapid-gossip-sync" version = "0.0.116-alpha1" -source = "git+https://github.com/tnull/rust-lightning?branch=2023-07-expose-default-message-router#73ba28d8e4efca44a6c4848c06697661988e6931" +source = "git+https://github.com/sr-gi/rust-lightning?rev=2239fe45bf10367789160a73120ad70ba42482e3#2239fe45bf10367789160a73120ad70ba42482e3" dependencies = [ "bitcoin", "lightning", diff --git a/Cargo.toml b/Cargo.toml index 6d466faf..33cb428e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,13 +24,13 @@ edition = "2018" #lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev="0d1072b7c3fb5366742473c38069c421cdd60b87", features = [ "futures" ] } #lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev="0d1072b7c3fb5366742473c38069c421cdd60b87" } -lightning = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router", features = ["max_level_trace"] } -lightning-block-sync = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router", features = ["rpc-client"] } -lightning-invoice = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router"} -lightning-net-tokio = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router" } -lightning-persister = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router" } -lightning-background-processor = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router", features = ["futures"] } -lightning-rapid-gossip-sync = { git = "https://github.com/tnull/rust-lightning", branch = "2023-07-expose-default-message-router"} +lightning = { git = "https://github.com/sr-gi/rust-lightning", rev = "2239fe45bf10367789160a73120ad70ba42482e3", features = ["max_level_trace"] } +lightning-block-sync = { git = "https://github.com/sr-gi/rust-lightning", rev = "2239fe45bf10367789160a73120ad70ba42482e3", features = ["rpc-client"] } +lightning-invoice = { git = "https://github.com/sr-gi/rust-lightning", rev = "2239fe45bf10367789160a73120ad70ba42482e3"} +lightning-net-tokio = { git = "https://github.com/sr-gi/rust-lightning", rev = "2239fe45bf10367789160a73120ad70ba42482e3" } +lightning-persister = { git = "https://github.com/sr-gi/rust-lightning", rev = "2239fe45bf10367789160a73120ad70ba42482e3" } +lightning-background-processor = { git = "https://github.com/sr-gi/rust-lightning",rev = "2239fe45bf10367789160a73120ad70ba42482e3", features = ["futures"] } +lightning-rapid-gossip-sync = { git = "https://github.com/sr-gi/rust-lightning", rev = "2239fe45bf10367789160a73120ad70ba42482e3"} base64 = "0.13.0" bitcoin = "0.29.0" diff --git a/src/main.rs b/src/main.rs index 8e870a24..03bdca8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,9 +5,12 @@ mod convert; mod disk; mod hex_utils; mod sweep; +mod tower; use crate::bitcoind_client::BitcoindClient; use crate::disk::FilesystemLogger; +use crate::tower::WatchtowerPersister; + use bitcoin::blockdata::transaction::Transaction; use bitcoin::consensus::encode; use bitcoin::network::constants::Network; @@ -30,7 +33,6 @@ use lightning::routing::router::DefaultRouter; use lightning::routing::scoring::ProbabilisticScoringFeeParameters; use lightning::sign::{EntropySource, InMemorySigner, KeysManager, SpendableOutputDescriptor}; use lightning::util::config::UserConfig; -use lightning::util::persist::KVStorePersister; use lightning::util::ser::ReadableArgs; use lightning_background_processor::{process_events_async, GossipSync}; use lightning_block_sync::init; @@ -87,7 +89,7 @@ type ChainMonitor = chainmonitor::ChainMonitor< Arc, Arc, Arc, - Arc, + Arc, >; pub(crate) type PeerManager = SimpleArcPeerManager< @@ -110,7 +112,7 @@ async fn handle_ldk_events( channel_manager: &Arc, bitcoind_client: &BitcoindClient, network_graph: &NetworkGraph, keys_manager: &KeysManager, inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage, - persister: &Arc, network: Network, event: Event, + persister: &Arc, network: Network, event: Event, ) { match event { Event::FundingGenerationReady { @@ -454,7 +456,7 @@ async fn start_ldk() { let broadcaster = bitcoind_client.clone(); // Step 4: Initialize Persist - let persister = Arc::new(FilesystemPersister::new(ldk_data_dir.clone())); + let persister = Arc::new(WatchtowerPersister::new(ldk_data_dir.clone())); // Step 5: Initialize the ChainMonitor let chain_monitor: Arc = Arc::new(chainmonitor::ChainMonitor::new( @@ -733,12 +735,12 @@ async fn start_ldk() { }; // Step 19: Persist ChannelManager and NetworkGraph - let persister = Arc::new(FilesystemPersister::new(ldk_data_dir.clone())); + let fs_persister = Arc::new(FilesystemPersister::new(ldk_data_dir.clone())); // Step 20: Background Processing let (bp_exit, bp_exit_check) = tokio::sync::watch::channel(()); let background_processor = tokio::spawn(process_events_async( - Arc::clone(&persister), + fs_persister, event_handler, chain_monitor.clone(), channel_manager.clone(), diff --git a/src/sweep.rs b/src/sweep.rs index a9ad6bdd..0527b5fe 100644 --- a/src/sweep.rs +++ b/src/sweep.rs @@ -7,17 +7,16 @@ use std::{fs, io}; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::sign::{EntropySource, KeysManager, SpendableOutputDescriptor}; use lightning::util::logger::Logger; -use lightning::util::persist::KVStorePersister; use lightning::util::ser::{Readable, WithoutLength}; use bitcoin::secp256k1::Secp256k1; use bitcoin::{LockTime, PackedLockTime}; use crate::hex_utils; +use crate::tower::WatchtowerPersister; use crate::BitcoindClient; use crate::ChannelManager; use crate::FilesystemLogger; -use crate::FilesystemPersister; /// If we have any pending claimable outputs, we should slowly sweep them to our Bitcoin Core /// wallet. We technically don't need to do this - they're ours to spend when we want and can just @@ -29,7 +28,7 @@ use crate::FilesystemPersister; /// we don't do that here either. pub(crate) async fn periodic_sweep( ldk_data_dir: String, keys_manager: Arc, logger: Arc, - persister: Arc, bitcoind_client: Arc, + persister: Arc, bitcoind_client: Arc, channel_manager: Arc, ) { // Regularly claim outputs which are exclusively spendable by us and send them to Bitcoin Core. diff --git a/src/tower.rs b/src/tower.rs new file mode 100644 index 00000000..27a99397 --- /dev/null +++ b/src/tower.rs @@ -0,0 +1,151 @@ +use std::collections::{HashMap, VecDeque}; +use std::ops::Deref; +use std::sync::Mutex; + +use bitcoin::blockdata::transaction::Transaction; +use bitcoin::hash_types::{BlockHash, Txid}; + +use lightning::chain; +use lightning::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW; +use lightning::chain::chainmonitor::{self, MonitorUpdateId}; +use lightning::chain::channelmonitor::{self, ChannelMonitor, RevokeableOutputData}; +use lightning::chain::transaction::OutPoint; +use lightning::sign::{self, EntropySource, SignerProvider}; +use lightning::util::persist::KVStorePersister; +use lightning::util::ser::Writeable; +use lightning_persister::FilesystemPersister; + +// number_of_witness_elements + sig_length + revocation_sig + true_length + op_true + witness_script_length + witness_script +pub(crate) const WEIGHT_REVOKED_OUTPUT: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 77; + +pub(crate) struct WatchtowerPersister { + persister: FilesystemPersister, + /// Upon a new commitment signed, we'll get a + /// ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTxInfo. We'll store the commitment txid + /// and revokeable output index and value to use to form the justice tx once we get a + /// revoke_and_ack with the commitment secret. + revokeable_output_data: Mutex>>, + /// After receiving a revoke_and_ack for a commitment number, we'll form and store the justice + /// tx which would be used to provide a watchtower with the data it needs. + watchtower_state: Mutex>>, +} + +impl WatchtowerPersister { + pub(crate) fn new(path_to_channel_data: String) -> Self { + WatchtowerPersister { + persister: FilesystemPersister::new(path_to_channel_data), + revokeable_output_data: Mutex::new(HashMap::new()), + watchtower_state: Mutex::new(HashMap::new()), + } + } + + pub(crate) fn justice_tx( + &self, funding_txo: OutPoint, commitment_txid: &Txid, + ) -> Option { + self.watchtower_state + .lock() + .unwrap() + .get(&funding_txo) + .unwrap() + .get(commitment_txid) + .cloned() + } + + pub fn persist(&self, key: &str, object: &W) -> std::io::Result<()> { + self.persister.persist(key, object) + } + + pub fn read_channelmonitors( + &self, entropy_source: ES, signer_provider: SP, + ) -> std::io::Result::Signer>)>> + where + ES::Target: EntropySource + Sized, + SP::Target: SignerProvider + Sized, + { + self.persister.read_channelmonitors(entropy_source, signer_provider) + } +} + +impl chainmonitor::Persist + for WatchtowerPersister +{ + fn persist_new_channel( + &self, funding_txo: OutPoint, data: &channelmonitor::ChannelMonitor, + id: MonitorUpdateId, + ) -> chain::ChannelMonitorUpdateStatus { + assert!(self + .revokeable_output_data + .lock() + .unwrap() + .insert(funding_txo, VecDeque::new()) + .is_none()); + assert!(self + .watchtower_state + .lock() + .unwrap() + .insert(funding_txo, HashMap::new()) + .is_none()); + println!("Initial commitment"); + self.persister.persist_new_channel(funding_txo, data, id) + // TODO: accomodate for first channel update + } + + fn update_persisted_channel( + &self, funding_txo: OutPoint, update: Option<&channelmonitor::ChannelMonitorUpdate>, + data: &channelmonitor::ChannelMonitor, update_id: MonitorUpdateId, + ) -> chain::ChannelMonitorUpdateStatus { + if let Some(update) = update { + // Track new counterparty commitment txs + let revokeable_output_data = data.revokeable_output_data_from_update(update); + let mut channels_revokeable_output_data = self.revokeable_output_data.lock().unwrap(); + let channel_state = channels_revokeable_output_data.get_mut(&funding_txo).unwrap(); + channel_state.extend(revokeable_output_data.into_iter()); + + // Form justice txs for revoked counterparty commitment txs + while let Some(RevokeableOutputData { + commitment_number, + commitment_txid, + output_idx, + value, + }) = channel_state.front() + { + let mut justice_tx = + data.build_justice_tx(*commitment_txid, *output_idx as u32, *value); + + // Fee estimation + let weight = justice_tx.weight() as u64 + WEIGHT_REVOKED_OUTPUT; + let min_feerate_per_kw = FEERATE_FLOOR_SATS_PER_KW; + let fee = min_feerate_per_kw as u64 * weight / 1000; + justice_tx.output[0].value -= fee; + + // Sign justice tx + let input_idx = 0; + match data.sign_justice_tx(justice_tx, input_idx, *value, *commitment_number) { + Ok(signed_justice_tx) => { + println!( + "Channel updated ({}). commitment_txid: {}, penalty: {:?}", + commitment_number, commitment_txid, signed_justice_tx + ); + let dup = self + .watchtower_state + .lock() + .unwrap() + .get_mut(&funding_txo) + .unwrap() + .insert(*commitment_txid, signed_justice_tx); + assert!(dup.is_none()); + channel_state.pop_front(); + } + Err(_) => break, + } + } + } + self.persister.update_persisted_channel(funding_txo, update, data, update_id) + } +} + +// impl KVStorePersister for WatchtowerPersister { +// fn persist(&self, key: &str, object: &W) -> std::io::Result<()> { +// self.persister.persist(key, object) +// } +// }