-
Notifications
You must be signed in to change notification settings - Fork 100
Add support for sourcing chain data from Electrum #486
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
base: main
Are you sure you want to change the base?
Conversation
b386ee7
to
9352b2e
Compare
568d10d
to
678cf91
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.
I'm familiarizing myself with the codebase but I tried running a node locally with the changes here pointing to an electrum server and basic operations are working. I just have a couple of questions, if I may, to get a better understanding.
Not strictly related to the PR but maybe I can sneak it in, why is it that for bitcoin core rpc and electrum they are in their separate bitcoind_rpc.rs
and electrum.rs
files but for esplora it is all in the mod.rs
? I see that that the EsploraAsyncClient
is directly used without a wrapper but wanted to see what were the reasons for it (:
Hmm, for one it has historic reasons, but also
Right, that's essentially the main reason why it still lives in |
9608e66
to
3142c41
Compare
466ab9f
to
e39b1f2
Compare
Blocked on rust-bitcoin/corepc#111 for now. |
0d401fe
to
dda6bc7
Compare
dda6bc7
to
edb4b10
Compare
Rebased on |
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.
The question that I asked myself most during review is whether the way this PR deals with the runtime and start/stop is really the best option for now.
edb4b10
to
97f4bd9
Compare
96ee279
to
cb5dc5b
Compare
Squashed fixups without further 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.
Nearly there. Just the one question about the double timeouts.
|
||
let spawn_fut = self.runtime.spawn_blocking(move || electrum_client.batch_call(&batch)); | ||
|
||
let timeout_fut = tokio::time::timeout( |
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.
I see you also set retries now. I saw that it was 1 previously (the default). Did the earlier test with the wifi disconnect pass because that one retry happened after you already reconnected wifi?
If I understand this correctly, setting the timeout on the electrum client itself is essential to not end up with a potential graveyard of stuck threads? This might be important to add as a comment.
Also curious to hear why you think that retrying over and over again when a previous request is still stuck is a good idea? It will eventually exhaust the thread pool, right? And then stop independent processes within LDK too?
The original reason for the double timeout is because esplora-client turned out to be not trustworthy. But, as suggested above, isn't electrum different because it isn't an async library and it is unlikely for the timeout to fail? Looking at the sources, it seems that the timeout is set on a pretty low level for all calls.
.. we need to bump the version, while making sure `electrsd` and CLN CI are using the same version. As the `blockstream/bitcoind` version hasn't reached v28 yet, we opt for v27.2 everywhere for now.
cb5dc5b
to
db756c6
Compare
The |
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.
I have taken another look at this PR and now understand why you apply pending filter entries to the pending transaction and output vectors. The refactor that introduced ElectrumRuntimeStatus
made it easier to reason about it as a state machine with the attendant events, actions, and state or internal transitions.
From the snippet below, when we start the Node
with the tokio runtime, it indicates that other background tasks do not get started before the ChainSource
has started:
pub fn start_with_runtime(&self, runtime: Arc<tokio::runtime::Runtime>) -> Result<(), Error> {
...
// Start up any runtime-dependant chain sources (e.g. Electrum)
self.chain_source.start(Arc::clone(&runtime)).map_err(|e| {
log_error!(self.logger, "Failed to start chain syncing: {}", e);
e
})?;
...
// Other background tasks
This suggests that it is unlikely that Confirm
ables would register transactions and outputs prior the chain source starting and, in extension, prior to the runtime client being available (ElectrumRuntimeStatus::Started
). Are there scenarios I am missing where this could happen? I'd appreciate any further clarification.
Otherwise, the PR looks good to me. Reviewing this has been quite educational. Thank you!
Thank you for the review!
Unfortunately, the and In turn we currently call this upon initialization: Line 1235 in 5abb42f
not at runtime/during |
37d667c
to
24d0874
Compare
We upgrade our tests to use `electrum-client` v0.22 and `electrsd` v0.31 to ensure compatibility with `bdk_electrum` were about to start using.
By default `rustls`, our TLS implementation of choice, uses `aws-lc-rs` which requires `bindgen` on some platforms. To allow building with `aws-lc-rs` on Android, we here install the `bindgen-cli` tool before running the bindings generation script in CI.
We here setup the basic API and structure for the `ChainSource::Electrum`. Currently, we won't have a `Runtime` available when initializing `ChainSource::Electrum` in `Builder::build`. We therefore isolate any runtime-specific behavior into an `ElectrumRuntimeClient`. This might change in the future, but for now we do need this workaround.
Currently, we won't have a `Runtime` available when initializing `ChainSource::Electrum`. We therefore isolate any runtime-specific behavior into the `ElectrumRuntimeStatus`. Here, we implement `Filter` for `ElectrumRuntimeClient`, but we need to cache the registrations as they might happen prior to `ElectrumRuntimeClient` becoming available.
.. as we do with `BitcoindRpc`, we now test `Electrum` support by running the `full_cycle` test in CI.
24d0874
to
5cdd2e3
Compare
Squashed fixups without further 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!
Still interested to see if conversion to a more object-oriented style for the backends is straight-forward or not.
Closes #196.
So far, we support Esplora and Bitcoind RPC chain sources. In this PR we add Electrum support based on the blocking
rust-electrum-client
, and it'sbdk_electrum
andlightning-transaction-sync
counterparts.Due to the blocking nature of
rust-electrum-client
and as it directly connects to the server uponClient::new
(see bitcoindevkit/rust-electrum-client#166), we ended up wrapping the runtime-specific behavior in anElectrumRuntimeClient
object that is initialized and dropped inNode::start
andstop
, respectively.One thing missing that we still need to consider is how we'd reestablish connections to the remote after they have been lost for one reason or another. IMO, that behavior should live inrust-electrum-client
to avoid all users having to duplicate it, so it's pending resolution of bitcoindevkit/rust-electrum-client#165As we did with
bitcoind
-RPC, Electrum support is tested by adding anotherfull_cycle
integration test.