-
Notifications
You must be signed in to change notification settings - Fork 374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement the UtxoSource interface for REST/RPC clients #2248
Conversation
aaff5be
to
2edc4f4
Compare
Codecov ReportPatch coverage:
❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more. Additional details and impacted files@@ Coverage Diff @@
## main #2248 +/- ##
==========================================
+ Coverage 90.33% 90.44% +0.10%
==========================================
Files 106 106
Lines 55732 56698 +966
Branches 55732 56698 +966
==========================================
+ Hits 50347 51279 +932
- Misses 5385 5419 +34
☔ View full report in Codecov by Sentry. |
c241108
to
7c51581
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a first pass for docs. Will look at caching a bit more in depth still today.
7c51581
to
69ad06e
Compare
Unfortunately, this seems to be in need of a rebase. |
69ad06e
to
0bef89d
Compare
Rebased (just needed a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass, generally things make sense. Correct me if I'm wrong, but the goal here is more to provide an implementation of UtxoLookup
right? And implementing UtxoSource
makes it easier to do so since you can just provide that to GossipVerifier
instead of implementing UtxoLookup
directly? The PR description confused me a little initially since it's mainly talking about UtxoSource
let pm = Arc::clone(&self.peer_manager); | ||
self.spawn.spawn(async move { | ||
let res = Self::retrieve_utxo(source, block_cache, short_channel_id).await; | ||
fut.resolve(gossiper.network_graph(), &*gossiper, res); | ||
pm.process_events(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it necessary to call PeerManager::process_events
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
process_events
has to be called cause we now have a pending outbound message waiting to be sent (or possibly we are ready to process more messages from the peer's socket, which we stopped reading from cause we were busy). If we don't call it, the message will go out when we next hit a timer tick in the background processor (or some other regular event calls it for us) but this may be a while.
Right, a user could implement |
0bef89d
to
8cf0271
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good I think!
let recent_blocks = block_cache.lock().unwrap(); | ||
for (height, block) in recent_blocks.iter() { | ||
if *height == block_height { | ||
process_block!(block); | ||
break 'tx_found; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making a note that since we don't move the block to the end of the queue here, we may pop off a block even though it's been used recently - probably not a big deal, but just something that popped up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I think its fine. Making it LRU is possible, but we'd have to shift the array, which isn't bad but is kinda annoying. Also, I don't think the behavior of "LRFirstUsed" is all that bad, either, really.
This is actually a valid response in some cases, at least for the `gettxout` command, where `null` is returned if no corresponding UTXO was found, but the command otherwise succeeded.
d626657
to
80aab12
Compare
Rebased with a trivial syntax fix to hopefully fix CI. |
117532c
to
a5cb5e3
Compare
a5cb5e3
to
da20a14
Compare
Squashed fixups without changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but will try to test this with the sample before approving
da20a14
to
71452c0
Compare
I've been running this on my sample node on mainnet since basically when this PR was open, do you want a patch or do you want to try to do it to see how hard the API is to use? |
Feel free to squash but CI needs a small fix. |
71452c0
to
b691d4d
Compare
Pushed incorporating the required fix:
|
In LDK, we expect users operating nodes on the public network to implement the `UtxoSource` interface in order to validate the gossip they receive from the network. Sadly, because the DoS attack of flooding a node's gossip store isn't a common issue, and because we do not provide an implementation off-the-shelf to make doing so easily, many of our downstream users do not have a `UtxoSource` implementation. In order to change that, here we implement an async `UtxoSource` in the `lightning-block-sync` crate, providing one for users who sync the chain from Bitcoin Core's RPC or REST interfaces.
Because a `UtxoLookup` implementation is likely to need a reference to the `PeerManager` which contains a reference to the `P2PGossipSync`, it is likely to be impossible to get a mutable reference to the `P2PGossipSync` by the time we want to add a `UtxoLookup` without a ton of boilerplate and trait wrapping. Instead, we simply place the `UtxoLookup` in a `RwLock`, allowing us to modify it without a mutable self reference. The lifetime bounds updates in tests required in this commit are entirely unclear to me, but do allow tests to continue building, so somehow make rustc happier.
The BOLT spec mandates that channels not be announced until they have at least six confirmations. This is important to enforce not because we particularly care about any specific DoS concerns, but because if we do not we may have to handle reorgs of channel funding transactions which change their SCID or have conflicting SCIDs.
b691d4d
to
189c1fb
Compare
|
||
let block_hash = source.get_block_hash_by_height(block_height).await | ||
.map_err(|_| UtxoLookupError::UnknownTx)?; | ||
let block_data = source.get_block(&block_hash).await |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could end up fetching the block multiple times here since we're not holding the lock, but probably not a big deal since we're already ok with the bandwidth costs associated with P2P sync and validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, and we can't hold the lock across an await point. It does suck, I agree, but storing and poll'ing other futures sounded hard 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
/// | ||
/// If the `tokio` feature is enabled, this is implemented on `TokioSpawner` struct which | ||
/// delegates to `tokio::spawn()`. | ||
pub trait FutureSpawner : Send + Sync + 'static { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-blocking nit: Technically this does not spawn futures but tasks. :P
One day we may be able to replace that with an std
trait: rust-lang/wg-async#283
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-blocking nit: Technically this does not spawn futures but tasks. :P
bleh. if you think its gonna confuse anyone ill change it but i doubt it otherwise.
One day we may be able to replace that with an std trait: rust-lang/wg-async#283
Yea, rust async is such an MVP...sadly its gotten all hung up on deciding big hairy decisions so never really got past MVP :(
In LDK, we expect users operating nodes on the public network to
implement the
UtxoSource
interface in order to validate thegossip they receive from the network.
Sadly, because the DoS attack of flooding a node's gossip store
isn't a common issue, and because we do not provide an
implementation off-the-shelf to make doing so easily, many of our
downstream users do not have a
UtxoSource
implementation.In order to change that, here we implement an async
UtxoSource
in the
lightning-block-sync
crate, providing one for users whosync the chain from Bitcoin Core's RPC or REST interfaces.