Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -53,6 +53,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 @@ -2550,6 +2551,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 @@ -2601,6 +2609,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,669 changes: 1,669 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
50 changes: 50 additions & 0 deletions src/data_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,19 @@ 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 @@ -1246,6 +1259,43 @@ mod tests {
assert_eq!(Some(expected), data_store.get(&id).await.unwrap());
}

#[tokio::test]
async fn mutate_async_awaits_fallible_reads() {
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(InMemoryStore::new()));
let logger = Arc::new(TestLogger::new());
let id = TestObjectId { id: [42u8; 4] };
let other_id = TestObjectId { id: [43u8; 4] };
let existing_object = TestObject::new(id, [23u8; 3]);
let other_object = TestObject::new(other_id, [24u8; 3]);
let data_store: DataStore<TestObject, Arc<TestLogger>> = DataStore::new(
vec![existing_object],
KeepAllEntries,
TEST_PRIMARY_NAMESPACE.to_string(),
TEST_SECONDARY_NAMESPACE.to_string(),
Arc::clone(&store),
Arc::clone(&logger),
);
let other_store: DataStore<TestObject, Arc<TestLogger>> = DataStore::new(
vec![other_object],
KeepAllEntries,
"other_datastore_test_primary".to_string(),
"other_datastore_test_secondary".to_string(),
store,
logger,
);

let result = data_store
.mutate_async(&id, |existing| async move {
let mut updated = existing.unwrap();
updated.data = other_store.get(&other_id).await?.unwrap().data;
Ok(Some(updated))
})
.await;
let expected = TestObject::new(id, [24u8; 3]);
assert_eq!(Ok(Some(expected)), result);
assert_eq!(Some(expected), data_store.get(&id).await.unwrap());
}

#[tokio::test]
async fn mutate_runs_the_closure_without_the_cache_lock() {
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(InMemoryStore::new()));
Expand Down
Loading
Loading