Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9f6aafb
Persist splice intents until the splice locks
jkczyz Oct 2, 2026
ec594a2
f - Persist splice intents until the splice locks
jkczyz Oct 26, 2026
6697fe0
f - Match a signed round's record in concerns_channel
jkczyz Oct 29, 2026
d8d6fca
f - Drop a redundant payment record removal
jkczyz Oct 29, 2026
a524fad
f - Name the lock-time intent check after what it classifies
jkczyz Oct 30, 2026
e5c83e6
f - Name the lock-time intent check after the splice lock
jkczyz Oct 30, 2026
3e0d899
Abort a splice when funding signing fails
jkczyz Sep 30, 2026
ed8a7ba
Add reason and splice parameters to splice failure events
jkczyz Sep 30, 2026
e516fdf
f - Document that a force-close failure has no splice parameters
jkczyz Oct 29, 2026
b956539
Unlock lost splice inputs at startup
jkczyz Sep 30, 2026
3c84d05
f - Unlock lost splice inputs at startup
jkczyz Oct 26, 2026
3155c91
f - Say why reconcile skips an intent the settle pass re-anchored
jkczyz Oct 29, 2026
739ba2e
f - Name the startup splice check after the question it answers
jkczyz Oct 30, 2026
95523e0
f - Say plainly why reconcile skips a channel's other stale intents
jkczyz Oct 30, 2026
95361b3
f - Say a splice locked where startup docs said the funding moved
jkczyz Oct 30, 2026
5889636
Test splice failure surfacing and recovery
jkczyz Sep 30, 2026
0a29a79
Refuse to sign a round this node cannot measure
tnull Sep 30, 2026
b29c554
Take back a splice intent its payment left behind
tnull Sep 29, 2026
4a08a3f
Let the funding output alone identify a funding
tnull Sep 29, 2026
957275d
Drop the DataStore::mutate_async wrapper
jkczyz Oct 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ use lightning_dns_resolver::OMDomainResolver;
use vss_client::headers::VssHeaderProvider;

use crate::chain::ChainSource;
use crate::channel::SpliceTracker;
#[cfg(feature = "chain-bitcoind")]
use crate::config::BitcoindRestClientConfig;
use crate::config::{
Expand Down Expand Up @@ -2565,6 +2566,13 @@ fn build_with_store_internal(
})
});

let splice_tracker = Arc::new(SpliceTracker::new(
Arc::clone(&channel_manager),
Arc::clone(&wallet),
Arc::clone(&pending_payment_store),
Arc::clone(&logger),
));

#[cfg(cycle_tests)]
let mut _leak_checker = crate::LeakChecker(Vec::new());
#[cfg(cycle_tests)]
Expand Down Expand Up @@ -2616,6 +2624,7 @@ fn build_with_store_internal(
payment_store,
forwarding_store,
forwarded_payment_aggregation_retention_secs,
splice_tracker,
lnurl_auth,
is_running,
node_metrics,
Expand Down
1,665 changes: 1,665 additions & 0 deletions src/channel/mod.rs

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,10 @@ pub(crate) const CHANNEL_TX_FACTS_MAX_RECORD_BYTES: usize = 128 * 1024;
// Records are dropped only once the channels they belong to have resolved, so between prunes a
// counterparty opening and closing channels, or replacing a negotiated funding again and again,
// drives the store's growth. Past this many records the store is full and the transactions
// it would have described go unclassified, which is bounded loss of detail rather than unbounded
// storage.
// it would have described go unclassified, which is bounded loss of detail rather than
// unbounded storage. An interactive funding round this node is about to sign is admitted beside
// them: how many of those there are is this node's own decision, and refusing one would cost a
// figure that is never corrected rather than a detail.
pub(crate) const CHANNEL_TX_FACTS_MAX_RECORDS: usize = 100_000;

// The number of pages of channel transaction provenance records one chain tip change examines.
Expand Down
24 changes: 8 additions & 16 deletions src/data_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,12 @@ where
self.mutate_with(id, |current| async move { Ok(f(current.as_ref())) }).await
}

async fn mutate_with<F, Fut>(&self, id: &SO::Id, f: F) -> Result<Option<SO>, Error>
/// Like [`Self::mutate`], but allows the transformation to await fallible reads.
///
/// The mutation lock remains held while `f` runs. This is useful when the new state must be
/// decided from an async read of another store without letting a concurrent writer invalidate
/// that decision. Callers must keep cross-store lock ordering consistent to avoid deadlocks.
pub(crate) async fn mutate_with<F, Fut>(&self, id: &SO::Id, f: F) -> Result<Option<SO>, Error>
where
F: FnOnce(Option<SO>) -> Fut,
Fut: Future<Output = Result<Option<SO>, Error>>,
Expand All @@ -470,19 +475,6 @@ where
Ok(Some(new_object))
}

/// Like [`Self::mutate`], but allows the transformation to await fallible reads.
///
/// The mutation lock remains held while `f` runs. This is useful when the new state must be
/// decided from an async read of another store without letting a concurrent writer invalidate
/// that decision. Callers must keep cross-store lock ordering consistent to avoid deadlocks.
pub(crate) async fn mutate_async<F, Fut>(&self, id: &SO::Id, f: F) -> Result<Option<SO>, Error>
where
F: FnOnce(Option<SO>) -> Fut,
Fut: Future<Output = Result<Option<SO>, Error>>,
{
self.mutate_with(id, f).await
}

/// Returns whether an object is stored under `id`.
pub(crate) async fn contains_key(&self, id: &SO::Id) -> Result<bool, Error> {
let _guard = self.mutation_lock.read().await;
Expand Down Expand Up @@ -1260,7 +1252,7 @@ mod tests {
}

#[tokio::test]
async fn mutate_async_awaits_fallible_reads() {
async fn mutate_with_awaits_fallible_reads() {
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(InMemoryStore::new()));
let logger = Arc::new(TestLogger::new());
let id = TestObjectId { id: [42u8; 4] };
Expand All @@ -1285,7 +1277,7 @@ mod tests {
);

let result = data_store
.mutate_async(&id, |existing| async move {
.mutate_with(&id, |existing| async move {
let mut updated = existing.unwrap();
updated.data = other_store.get(&other_id).await?.unwrap().data;
Ok(Some(updated))
Expand Down
Loading
Loading