Skip to content
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

Improve on (potentially) blocking wallet behaviors #281

Merged
merged 13 commits into from
Jun 20, 2024

Conversation

tnull
Copy link
Collaborator

@tnull tnull commented Apr 12, 2024

Based on #141.

Due to our onchain wallet requiring us to hold a Mutex for the duration of the chain sync, many operations might be blocked for seconds at at time.

Here, we make several changes that hopefully alleviate any blocking issues from holding the wallet lock(s). In particular we introduce a balance cache, drop our 'immediate retry sync' logic and drop the previous wallet_lock Condvar in favor of a pub/sub pattern that is beneficial in async runtime environments.

@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch from 3d70262 to c0f13bc Compare April 12, 2024 13:00
@tnull tnull changed the title Improve on wallet (potentially) blocking wallet behaviors Improve on (potentially) blocking wallet behaviors Apr 12, 2024
@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch 13 times, most recently from 8edbac9 to d4649e8 Compare May 17, 2024 12:42
@tnull tnull added this to the 0.3 milestone May 20, 2024
@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch from d4649e8 to abb6926 Compare June 1, 2024 07:57
@tnull
Copy link
Collaborator Author

tnull commented Jun 1, 2024

Rebased on #141 to resolve minor conflicts with main.

@tnull tnull mentioned this pull request Jun 11, 2024
@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch 2 times, most recently from 85affcf to 4abd601 Compare June 11, 2024 18:57
@tnull
Copy link
Collaborator Author

tnull commented Jun 11, 2024

Rebased on main after #141 landed.

@tnull tnull requested a review from jkczyz June 11, 2024 19:02
@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch from 4abd601 to fa7690b Compare June 14, 2024 07:27
@tnull
Copy link
Collaborator Author

tnull commented Jun 14, 2024

Rebased after #307 landed.

Copy link
Contributor

@jbesraa jbesraa left a comment

Choose a reason for hiding this comment

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

I tested this branch locally with an app with GUI that previously lagged when the wallet synced and I can confirm that with this PR things are much smoother

@tnull
Copy link
Collaborator Author

tnull commented Jun 14, 2024

I tested this branch locally with an app with GUI that previously lagged when the wallet synced and I can confirm that with this PR things are much smoother

Yeah, without these workarounds the post-Anchors code is borderline unusable as event handling might grind to a standstill whenever we need to check the balance and wallet syncing is ongoing.

@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch from fa7690b to 840ca4f Compare June 17, 2024 07:35
@tnull
Copy link
Collaborator Author

tnull commented Jun 17, 2024

Rebased to resolve minor conflict after #303 landed.

@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch from 840ca4f to a85fede Compare June 18, 2024 09:15
@tnull
Copy link
Collaborator Author

tnull commented Jun 18, 2024

Now also added a commit dropping the immediate-retry behavior in TxBroadcaster, and applying the timeout to tx_sync.sync() in sync_wallets

@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch 2 times, most recently from c1ff7a1 to 0e9caca Compare June 18, 2024 13:06
@tnull tnull requested a review from G8XSU June 18, 2024 17:58
*self.balance_cache.write().unwrap() = balance.clone();
balance
},
Err(_) => self.balance_cache.read().unwrap().clone(),
Copy link
Contributor

Choose a reason for hiding this comment

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

can you expand on some of the implications of using a cached balance ?

iiuc, we might bypass some of the balance checks during open-channel (outbound and inbound) and send_to_address.(does bdk allow building tx greater than balance?)

Copy link
Collaborator Author

@tnull tnull Jun 19, 2024

Choose a reason for hiding this comment

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

can you expand on some of the implications of using a cached balance ?

It essentially has no implications: generally the wallet balance would always just be updated when a sync succeeds and here we make sure to always update the cache afterwards, while still holding the wallet Mutex. So the cache should always be up to date. Plus, we'll actually call through and update the cache whenever we can.

iiuc, we might bypass some of the balance checks during open-channel (outbound and inbound) and send_to_address.(does bdk allow building tx greater than balance?)

Yes, but IIUC BDK's wallet would always only pick up on any changes after a successful sync, i.e., it would show the old balance anyways.

Btw, see relatedly: #41

@@ -175,13 +199,24 @@ where
pub(crate) fn get_balances(
Copy link
Contributor

Choose a reason for hiding this comment

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

might be worth to add doc that result might be cached.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I honestly don't think it matters: a) this is pub(crate), and b) it shouldn't result in any noticeable behavior changes, as discussed above.

src/wallet.rs Outdated
Err(e) => match e {
bdk::Error::Esplora(ref be) => match **be {
bdk::blockchain::esplora::EsploraError::Reqwest(_) => {
// Drop lock, sleep for a second, retry.
drop(wallet_lock);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we this and retry here, only to remove it in later commit, can be simplified if we just drop retry before this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fair enough. Are you fine with me leaving it like this or would you prefer to invert the commit ordering?

src/wallet.rs Outdated Show resolved Hide resolved
src/wallet.rs Outdated Show resolved Hide resolved
src/wallet.rs Outdated Show resolved Hide resolved
@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch 2 times, most recently from afee329 to fcb824f Compare June 20, 2024 16:39
@tnull
Copy link
Collaborator Author

tnull commented Jun 20, 2024

Kicked CI.

@G8XSU Let me know if I can squash the fixups.

@G8XSU
Copy link
Contributor

G8XSU commented Jun 20, 2024

Lgtm!
feel free to squash fixups.

tnull added 13 commits June 20, 2024 19:10
Unfortunately BDK's current wallet design requires us to have it live in `Mutex`
that is locked for long periods of time during syncing. This is
especially painful for short-lived operations that just operate locally,
such as retrieving the current balance, which we now do in several
places to be able to check Anchor channels limitations, e.g., in event
handling.

In order to avoid blocking during balance retrieval, we introduce a
`balance` cache that will be refreshed whenever we're done with syncing
*or* when we can successfully get the wallet lock. Otherwise, we'll just
return the cached value, allowing us to make progress even though a
background sync of the wallet might be in-progress.
Using a `Condvar` could be potentially dangerous in async contexts as
`wait`ing on it might block the current thread potentially hosting more
than one task. Here, we drop the `Condvar` and adopt a pub/sub scheme
instead, similar to the one we already implemented in
`ConnectionManager`.
It's not super clear that it achieves much in the face of a rate-limited
Esplora server, and having a custom sleep there is just awkward. So we
drop it and hope we still get a chance to sync our on-chain wallet now
and then.
.. as we're not sure it actually increases reliability.

We now only log failures, ignoring HTTP 400 as this is bitcoind's error
code for "transaction already in mempool".
.. to make progress and unblock the `Mutex` even if BDK's wallet `sync` would never return.
.. even though we don't expect this to block, we're better safe than
sorry and start to introduce timeouts for any calls we make to remote
servers.
.. even though we don't expect this to block, we're better safe than
sorry and start to introduce timeouts for any calls we make to remote
servers.
.. even though we don't expect this to block, we're better safe than
sorry and start to introduce timeouts for any calls we make to remote
servers.
.. before initiating the Runtime shutdown.
.. as we use `Clone` for `tokio::sync::watch::Sender`, which was only
introduced with 1.37.
@tnull tnull force-pushed the 2024-04-improve-on-wallet-friction branch from fcb824f to f839015 Compare June 20, 2024 17:10
@tnull
Copy link
Collaborator Author

tnull commented Jun 20, 2024

Lgtm! feel free to squash fixups.

Squashed without further changes.

@tnull tnull merged commit ca44721 into lightningdevkit:main Jun 20, 2024
6 of 13 checks passed
Sign up for free to 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.

3 participants