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

Rework and simplify electrum client, miniwallet and watcher #411

Merged
merged 4 commits into from
Mar 28, 2023

Conversation

sstone
Copy link
Member

@sstone sstone commented Nov 23, 2022

CompletableDeferred<> is used to handle multiple concurrent calls and provide suspend methods which are much easier to use. For example, to retrieve a transaction you can simply call client.getTx(txid) and you can chain such calls in your message handling loops: this eliminate the need to send messages to yourself and create intermediate states that are just waiting for a response from the electrum client.

I've also remove the NotifyTxEvent event which I believe is not used anywhere.

@sstone sstone requested review from pm47 and robbiehanson November 23, 2022 15:20
@robbiehanson
Copy link
Contributor

robbiehanson commented Nov 24, 2022

This looks like a nice cleanup!

I tested it in branch test-pr-411 and I ran into one issue.

The problem we're having on the Phoenix side is that ElectrumClient's connect()/disconnect() functions have been replaced with start()/stop(), but they don't do the same thing. From what I'm reading, start() is expected to be invoked once, and has it's own reconnection logic. And stop(), if invoked, prevents ElectrumClient from working again.

The issue is that, Phoenix has a better understanding of the network state than lightning-kmp. Specifically, it has a NetworkMonitor, which knows whether or not the device has an Intenet connection. This is obviously OS-specific (for example, here's the iOS version). And since Phoenix receives notifications from the OS about the network state, it can better determine when to attempt a re-connect.

And there are other complications. On iOS, when the app is sent into the background, the OS will kill any open network connections (after a brief delay). The Phoenix layer knows when the app is going to be sent to the background, and prefers to perform a clean disconnect on its own.

Unless of course an outgoing payment is in progress when the user background's the app. In which case Phoenix asks the OS for permission to perform a "long-lived background task". If granted, it then keeps the connection(s) open until the payment completes, or we run out of granted time.

There's also the WatchTower task, which runs every few days while the app is in the background...

Long story short, there are a bunch of complications surrounding connect/disconnect/reconnect. All this logic is implemented in AppConnectionsDaemon. (See AppConnectionsDaemon.TrafficControl) So I think it makes sense to remove the auto-reconnect logic from within ElectrumClient, and allow the external layer (e.g. Phoenix) to handle it instead. (This is also how Peer works - it outsources the reconnection logic.)

@sstone
Copy link
Member Author

sstone commented Nov 24, 2022

Sorry I missed that, I'll restore connect()/disconnect() to their original behaviour.

@sstone sstone marked this pull request as draft November 24, 2022 17:44
@sstone sstone force-pushed the electrum-client-rework branch from 0b11d32 to cb32535 Compare March 15, 2023 17:35
@sstone
Copy link
Member Author

sstone commented Mar 15, 2023

Rebased and updated to be 100% compatible with the current client and watcher (tested on Android but not on iOS).

@sstone sstone force-pushed the electrum-client-rework branch from cb32535 to 38935b6 Compare March 16, 2023 13:19
Copy link
Member

@dpad85 dpad85 left a comment

Choose a reason for hiding this comment

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

Tested on Phoenix Android and iOS, it works fine. There are issues with Tor in edge cases but I think they should be investigated separately.

@pm47
Copy link
Member

pm47 commented Mar 24, 2023

I have added a few nits on branch electrum-client-rework-pm.

Why is this PR draft, what's left to work on?

sstone added 2 commits March 26, 2023 19:48
CompletableDeferred<> is used to handle multiple concurrent calls and provide suspend methods which are much easier to use.
For example, to retrieve a transaction you can simply call `client.getTx(txid)` and you can chain such calls in your message handling loops:
this eliminate the need to send messages to yourself and create intermediate states that are just waiting for a response from the electrum client.

We also fix a bug where Phoenix would crash after being disconnected because it would try to use a closed socket to send Ping messages.
@sstone sstone force-pushed the electrum-client-rework branch from f66fd82 to 39136e6 Compare March 26, 2023 18:11
@sstone
Copy link
Member Author

sstone commented Mar 27, 2023

I have added a few nits on branch electrum-client-rework-pm.

Thanks, I used these changes and also updated ElectrumClient's notification flow to a Flow<ElectrumSubscriptionResponse>

Why is this PR draft, what's left to work on?

The only thing that I'm unsure of is the handling of NotifyUpToDateEvent but otherwise there is nothing missing that I know of or was reported so far, I'll update the PR status

@sstone sstone marked this pull request as ready for review March 27, 2023 08:48
pm47
pm47 previously approved these changes Mar 27, 2023
Copy link
Member

@pm47 pm47 left a comment

Choose a reason for hiding this comment

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

Code LGTM, but this requires an ACK from the Phoenix team.

dpad85
dpad85 previously approved these changes Mar 28, 2023
Copy link
Member

@dpad85 dpad85 left a comment

Choose a reason for hiding this comment

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

LGTM

@sstone
Copy link
Member Author

sstone commented Mar 28, 2023

LGTM

@dpad85 with or without ElectrumWatcher.openUpToDateFlow (see #411 (comment)) ? Or do you want to add that notification back in another PR ?

@dpad85
Copy link
Member

dpad85 commented Mar 28, 2023

So the removal of openUpToDateFlow should be reverted as it is needed by the background watcher in the iOS app. This is ad hoc code that should be cleaned up, but it's outside the scope of this PR.

It is used by a watch-tower module written in Swift in the iOS app.
Code has bee simplified and there are now 2 separate flows:
- one for watch events
- one for "up-to-date" events (which are just the number of milliseconds since the watcher is ready and idle)
@sstone sstone dismissed stale reviews from dpad85 and pm47 via 6ad2580 March 28, 2023 13:02
@sstone sstone force-pushed the electrum-client-rework branch from 3e16024 to 6ad2580 Compare March 28, 2023 13:02
@sstone
Copy link
Member Author

sstone commented Mar 28, 2023

I've restored openUpToDateFlow and simplified the watcher a bit (there is now one flow for watch events, one flow for up-to-date events)

@sstone sstone requested review from robbiehanson, pm47 and dpad85 March 28, 2023 13:40
@pm47 pm47 removed request for robbiehanson and pm47 March 28, 2023 14:02
@sstone sstone merged commit d36d723 into master Mar 28, 2023
@sstone sstone deleted the electrum-client-rework branch March 28, 2023 15:20
pm47 added a commit that referenced this pull request Jan 26, 2024
In the initial implementation of the wallet, we were asynchronously retrieving the parent transaction of utxos. When a new utxo was detected, there would be a period of time where `WalletState` would contain the utxo, but not the parent tx, hence the need for the `consistent` boolean.

But since #411 the Electrum interface has become "synchronous" with the use of `suspend` functions.

Note that if for some reason we cannot retrieve the transaction from Electrum, then we ignore the utxo, which is what we were doing previously with a `walletStateFlow.filter { it.consistent }` in Peer.
pm47 added a commit that referenced this pull request Jan 29, 2024
In the initial implementation of the wallet, we were asynchronously retrieving the parent transaction of utxos. When a new utxo was detected, there would be a period of time where `WalletState` would contain the utxo, but not the parent tx, hence the need for the `consistent` boolean.

But since #411 the Electrum interface has become "synchronous" with the use of `suspend` functions.

Note that if for some reason we cannot retrieve the transaction from Electrum, then we ignore the utxo, which is what we were doing previously with a `walletStateFlow.filter { it.consistent }` in Peer.
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.

4 participants