Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Persist NetworkGraph on removal of stale channels - #1376

Merged
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph
Mar 30, 2022
Merged

Persist NetworkGraph on removal of stale channels#1376
jkczyz merged 3 commits into
lightningdevkit:mainfrom
jurvis:jurvis/persist-networkgraph

Conversation

@jurvis

@jurvisjurvis commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

This PR addresses issue #1191. I borrowed mostly the same ideas from persisting ChannelManager, except instead of throwing an exception on error, I do a log_error! instead to mirror the non-terminal behavior in ldk-sample.

I'm also not sure if we want to be calling persist_network_graph at the same time as persist_manager, but I couldn't figure out how else to test it, since the prune block only gets called after 60 seconds. Let me know if there are any ideas here.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from b7f1396 to cc88533CompareMarch 22, 2022 03:27
@codecov-commenter

codecov-commenter commented Mar 22, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1376 (df2e60d) into main (c244c78) will increase coverage by 0.06%.
The diff coverage is 96.82%.

@@ Coverage Diff @@## main #1376 +/- ##
==========================================
+ Coverage 90.73% 90.80% +0.06% 
==========================================
Files 73 73 Lines 40808 41241 +433 Branches 40808 41241 +433 ==========================================
+ Hits 37027 37447 +420 - Misses 3781 3794 +13 
Impacted FilesCoverage Δ
lightning-background-processor/src/lib.rs95.20% <96.42%> (+2.09%)⬆️
lightning-persister/src/lib.rs93.93% <100.00%> (+0.33%)⬆️
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/ln/channel.rs88.29% <0.00%> (-0.92%)⬇️
lightning-net-tokio/src/lib.rs75.88% <0.00%> (-0.81%)⬇️
lightning/src/debug_sync.rs94.79% <0.00%> (-0.27%)⬇️
lightning/src/routing/scoring.rs94.04% <0.00%> (-0.26%)⬇️
lightning-invoice/src/de.rs81.06% <0.00%> (-0.21%)⬇️
lightning/src/ln/channelmanager.rs84.74% <0.00%> (-0.04%)⬇️
lightning/src/ln/functional_tests.rs97.06% <0.00%> (-0.03%)⬇️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c244c78...df2e60d. Read the comment docs.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks pretty good at first glance.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {
log_warn!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably log_error, I think, instead.

persister.persist_manager(&*channel_manager)?;
channel_manager_persister.persist_manager(&*channel_manager)?;
if let Some(ref handler) = net_graph_msg_handler {
if network_graph_persister.persist_graph(handler.network_graph()).is_err() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely don't need to persist the graph here, otherwise we'll be doing it every time we have any HTLC/commitment updates.

@jurvisjurvisMar 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's actually related to the question I had in the PR description... I added it here in order to test if NetworkGraph persists without waiting for 60 seconds for the prune block to run.

I was wondering if you had any ideas on that? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome to const-ify that 60 and then use #[cfg(test)] to have a different value in test, eg the way PING_TIMER and FRESHNESS_TIMER are done.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt ah, got it! didn't see that. Thanks! 😄

Comment threadlightning-background-processor/src/lib.rs
@jurvis
jurvis marked this pull request as ready for review March 23, 2022 17:46

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of rather trivial comments, but largely looks great, thanks!

Comment threadlightning-background-processor/src/lib.rs Outdated
/// Unlike, [`persist_manager`], this will not cause [`BackgroundProcessor`] to exit.
///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to drop this, no? By default the docs stuff will resolve any symbols which are resolvable locally.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it -- this is my first time working with rustdoc works so you're probably right 😄

///
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph
/// [`BackgroundProcessor`]: lightning-background-processor::BackgroundProcessor
/// [`persist_manager`]: lightning-background-processor::Persister::persist_manager

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note you shouldn't need the full crate reference here.

///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a number of places you have EOL whitespace. A local git show should highlight them based on your terminal settings.

/// provided implementation.
///
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk, and/or
/// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we want to suggest people back up the network graph, its all public data.

L::Target: 'static + Logger,
{
fn persist_manager(&self, _channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "test"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests, instead of erroring, we should panic to ensure the test fails.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this test is actually for testing if channel_manager persistence fails. I didn't change the original implementation of persist_manager in tests.

Right now it checks and panics if there isn't an error.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually that makes me wonder, and I apologize if this is a dumb question: since we only do log_error! instead of throwing it when persisting a graph fails, how do we test that behavior? do I use the testing_logger crate?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops lol sorry.

how do we test that behavior?

Our TestLogger struct has a few assert_log* functions that allow you to assert a regex or specific string was logged. We don't generally worry too much about ensuring particular log entries are printed, though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheBlueMatt gotcha -- in that case, I created a test that just does the same error checks as what we do for persisting channel_manager 😄

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it'd be great to persist the graph on exit like we do the channelmanager as well.

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch 3 times, most recently from c0f6a43 to 3685a6cCompareMarch 24, 2022 21:37
fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), std::io::Error> {
self(channel_manager)
}
/// Persist the given [`NetworkGraph`] to disk, logging an error if persistence failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is expected to return an error, not log it. The caller logs the error. I think in general method docs should describe the method's behavior, not the caller's.

}

// Persist NetworkGraph on exit
if let Some(ref handler) = net_graph_msg_handler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do this after the channel manager - the manager is much more important, and if the network graph fails to be persisted cause the user kills the process during shutdown its not a big deal.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you squash the commits down into one or two commits that stand alone without later fixups?

@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from 7621e4b to 1670e90CompareMarch 27, 2022 23:12
@jurvis

Copy link
Copy Markdown
ContributorAuthor

squashed

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Some of my comments predate your change but would be a good opportunity to fix now.

#[cfg(test)]
const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;

/// Trait which handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/which/that

Comment on lines +85 to +86
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
pub trait ChannelManagerPersister<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
/// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These mappings can be removed (here and below) since both structs are imported. Can verify by removing and running cargo doc -p lightning-background-processor

{
/// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.
/// (which will cause the [`BackgroundProcessor`] which called this method to exit.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: period after parenthesis.

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "Error:" given the logging level used?

log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
if persister.persist_graph(handler.network_graph()).is_err() {
log_error!(logger, "Warning: Failed to persist network graph, check your disk and permissions");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include the error in the log?


// Check network graph is persisted
let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
let mut expected_bytes = Vec::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having expected_bytes here is a bit confusing. Could you move it directly into check_persisted_data!?

fn test_network_graph_persist_error() {
// Test that if we encounter an error during network graph persistence, an error gets returned.
let nodes = create_nodes(2, "test_persist_network_graph_error".to_string());
open_channel!(nodes[0], nodes[1], 100000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this line is not necessary.

}
}

#[derive(Clone)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deriving Clone, create a new Persister where needed and clone the data dir to pass to it.

open_channel!(nodes[0], nodes[1], 100000);

let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test"));
struct ChannelManagerErrorPersister {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the duplication and boilerplate needed for the specialized persisters, you can modify the standard one you provided earlier as follows:

structPersister{data_dir:String,graph_error:Option<(std::io::ErrorKind,&'staticstr)>,}implPersister{fnnew(data_dir:String) -> Self{Self{ data_dir,graph_error:None}}fnwith_graph_error(self,error: std::io::ErrorKind,message:&'staticstr) -> Self{Self{graph_error:Some((error, message)), ..self}}}// ...fnpersist_graph(&self,network_graph:&NetworkGraph) -> Result<(), std::io::Error>{matchself.graph_error{None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph),Some((error, message)) => Err(std::io::Error::new(error, message)),}}

And then create one as:

let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other,"test");

This will make the tests easier to read as they'll be more concise. You can do something similar for ChannelManager persistence errors.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks really slick, will do this. thanks!

/// provided implementation.
///
/// Typically, users should either implement [`ChannelManagerPersister`] to never return an
/// `persist_graph` is responsible for writing out the [`NetworkGraph`] to disk. See

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the paragraphs above, I think the reference to persist_manager was at one point referring to a parameter to start but has been renamed a few times since. We should update the docs accordingly and use similar wording in this paragraph for persist_graph now that these are methods on persister.

@jurvis

Copy link
Copy Markdown
ContributorAuthor

thanks for the review @jkczyz! I made the changes and broke them up by commit. I'm a little unsure on what else needs to be done to the docs beyond explicitly saying that persist_manager is now called via an implementation of the Persister trait. Let me know if there is any specific language you will prefer to add 😄

jkczyz
jkczyz previously approved these changes Mar 29, 2022

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks great! Can squash again once @TheBlueMatt is good.

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

LGTM! Please squash the commits down into logically consistent commits without fixups in later commits and this should be good to go.

Instead of creating a separate trait for persisting NetworkGraph, use and rename the existing ChannelManagerPersister to handle them both. persist_graph is then called on removal of stale channels and on exit.
@jurvis
jurvisforce-pushed the jurvis/persist-networkgraph branch from de4cb40 to df2e60dCompareMarch 30, 2022 02:38
@jurvis

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt@jkczyz squashed. hope the way I organized the commits makes sense.

@jkczyz
jkczyz merged commit aeeafed into lightningdevkit:mainMar 30, 2022
jkczyz added a commit to jkczyz/rust-lightning that referenced this pull request Apr 1, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jurvis@codecov-commenter@TheBlueMatt@jkczyz