Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
sr-gi committed Jul 10, 2023
1 parent 364d47d commit fbc0fe1
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 23 deletions.
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
14 changes: 8 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -87,7 +89,7 @@ type ChainMonitor = chainmonitor::ChainMonitor<
Arc<BitcoindClient>,
Arc<BitcoindClient>,
Arc<FilesystemLogger>,
Arc<FilesystemPersister>,
Arc<WatchtowerPersister>,
>;

pub(crate) type PeerManager = SimpleArcPeerManager<
Expand All @@ -110,7 +112,7 @@ async fn handle_ldk_events(
channel_manager: &Arc<ChannelManager>, bitcoind_client: &BitcoindClient,
network_graph: &NetworkGraph, keys_manager: &KeysManager,
inbound_payments: &PaymentInfoStorage, outbound_payments: &PaymentInfoStorage,
persister: &Arc<FilesystemPersister>, network: Network, event: Event,
persister: &Arc<WatchtowerPersister>, network: Network, event: Event,
) {
match event {
Event::FundingGenerationReady {
Expand Down Expand Up @@ -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<ChainMonitor> = Arc::new(chainmonitor::ChainMonitor::new(
Expand Down Expand Up @@ -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(),
Expand Down
5 changes: 2 additions & 3 deletions src/sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<KeysManager>, logger: Arc<FilesystemLogger>,
persister: Arc<FilesystemPersister>, bitcoind_client: Arc<BitcoindClient>,
persister: Arc<WatchtowerPersister>, bitcoind_client: Arc<BitcoindClient>,
channel_manager: Arc<ChannelManager>,
) {
// Regularly claim outputs which are exclusively spendable by us and send them to Bitcoin Core.
Expand Down
152 changes: 152 additions & 0 deletions src/tower.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
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<HashMap<OutPoint, VecDeque<RevokeableOutputData>>>,
/// 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<HashMap<OutPoint, HashMap<Txid, Transaction>>>,
}

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<Transaction> {
self.watchtower_state
.lock()
.unwrap()
.get(&funding_txo)
.unwrap()
.get(commitment_txid)
.cloned()
}

pub fn persist<W: Writeable>(&self, key: &str, object: &W) -> std::io::Result<()> {
println!("SDS: Persisting");
self.persister.persist(key, object)
}

pub fn read_channelmonitors<ES: Deref, SP: Deref>(
&self, entropy_source: ES, signer_provider: SP,
) -> std::io::Result<Vec<(BlockHash, ChannelMonitor<<SP::Target as SignerProvider>::Signer>)>>
where
ES::Target: EntropySource + Sized,
SP::Target: SignerProvider + Sized,
{
self.persister.read_channelmonitors(entropy_source, signer_provider)
}
}

impl<Signer: sign::WriteableEcdsaChannelSigner> chainmonitor::Persist<Signer>
for WatchtowerPersister
{
fn persist_new_channel(
&self, funding_txo: OutPoint, data: &channelmonitor::ChannelMonitor<Signer>,
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<Signer>, 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<W: Writeable>(&self, key: &str, object: &W) -> std::io::Result<()> {
// self.persister.persist(key, object)
// }
// }

0 comments on commit fbc0fe1

Please sign in to comment.