Skip to content

Conversation

@tnull
Copy link
Contributor

@tnull tnull commented Jan 6, 2026

Closes #189.

I asked Claude Code to implement the changes necessary to update to the recently released Electrum Protocol v1.6.

Putting in draft for now until I got initial feedback (cc @oleonardolima @ValuedMammal). We also still need to change the test setup to a v1.6-compatible server to actually run the new tests against.

@tnull tnull marked this pull request as draft January 6, 2026 11:09
@tnull tnull force-pushed the 2026-01-protocol-v1.6 branch from 9c09893 to 93c20f9 Compare January 6, 2026 11:12
@tnull
Copy link
Contributor Author

tnull commented Jan 6, 2026

Hmm, test_local_timeout is currently failing, likely because we now need to successfully negotiate the version before returning the client. Though I have to say I don't fully understand what the test is for in the first place. Could someone explain what we try to assert there exactly?

@oleonardolima oleonardolima added the new feature New feature or request label Jan 6, 2026
@oleonardolima oleonardolima moved this to In Progress in BDK Chain Jan 6, 2026
@ValuedMammal
Copy link
Contributor

Concept ACK

@tnull tnull force-pushed the 2026-01-protocol-v1.6 branch from 93c20f9 to 114a3c1 Compare January 23, 2026 09:57
@tnull tnull marked this pull request as ready for review January 23, 2026 09:57
@tnull tnull force-pushed the 2026-01-protocol-v1.6 branch 4 times, most recently from 17f66bc to faeef85 Compare January 23, 2026 10:31
@tnull
Copy link
Contributor Author

tnull commented Jan 23, 2026

Alright, now updated the CI to use a v1.6 server for tests, fixed some minor things that came up, and opted to simply drop the test_local_timeouts test case as its dummy server implementation is incompatible with the v1.6 flow (that requires version negotiation). Let me know if you think that's acceptable @oleonardolima @ValuedMammal.

Undrafted, as this should be ready-to-go.

@tnull tnull force-pushed the 2026-01-protocol-v1.6 branch 3 times, most recently from e16260d to f689698 Compare January 23, 2026 11:27
Copy link
Contributor

@ValuedMammal ValuedMammal left a comment

Choose a reason for hiding this comment

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

I did a first pass, overall it looks reasonable. I left some nits and a few questions. I'm curious if you've had a chance to test this in the wild.

In 38386fe: "feat: Automatically negotiate protocol version on connect"

The commit message refers to a server_version() method that "updates the stored version", but that seems to be hallucinated.

tnull added 2 commits January 27, 2026 09:51
.. we just picked a random tcp-based server running Electrum X 1.19 with
decent uptime from https://1209k.com/bitcoin-eye/ele.php.
The local timeout test was introduce in
f30be3b as a wait to check that
connection timeouts work. However, it uses a pretty flaky setup to begin
with, requiring manual `iptables` rules in CI, and it leans on a dummy
server implementation that doesn't actually do anything besides
accepting the connection.

However, as with protocol v1.6 we now only consider the connection
successful (and for now return the `Client`) if the counterparty
responded to our version negotiation, we're now incompatible with the
dummy setup of `test_local_timeout`. Since I'm not sure how solid and
important the specific test coverage is to begin with, I here opted to
just drop the test case.
@tnull
Copy link
Contributor Author

tnull commented Jan 27, 2026

I did a first pass, overall it looks reasonable. I left some nits and a few questions. I'm curious if you've had a chance to test this in the wild.

No, we did not test this in the wild yet, though of course now the tests run against v1.6 mainnet servers, so they are somewhat an 'in the wild' test.

The commit message refers to a server_version() method that "updates the stored version", but that seems to be hallucinated.

Ah, not hallucinated, but this is a stale comment that referred to a previous approach that I ended up amending.

@tnull tnull requested a review from ValuedMammal January 27, 2026 09:07
@tnull tnull force-pushed the 2026-01-protocol-v1.6 branch from f689698 to 485c4b0 Compare January 27, 2026 09:15
tnull added 3 commits January 28, 2026 10:13
Send `server.version` as the first message after establishing a
connection, as required by Electrum protocol v1.6. The negotiated
protocol version is stored in `RawClient` and can be retrieved via
the new `protocol_version()` method.

- Add `CLIENT_NAME`, `PROTOCOL_VERSION_MIN`, `PROTOCOL_VERSION_MAX` constants
- Add `protocol_version` field to `RawClient` to store negotiated version
- All constructors (`new`, `new_ssl`, `new_ssl_from_stream`, `new_proxy`)
  now automatically call `server.version` after connecting

This is a breaking change as the constructors now return errors if
protocol negotiation fails.

Co-Authored-By: Claude Code AI
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add the `mempool.get_info` RPC method to the ElectrumApi trait. This
method was added in protocol v1.6 and provides more detailed mempool
fee information than the deprecated `blockchain.relayfee` method.

The response includes:
- `mempoolminfee`: Dynamic minimum fee rate for tx acceptance
- `minrelaytxfee`: Static operator-configured minimum relay fee
- `incrementalrelayfee`: Minimum fee rate increment for RBF/mempool limiting

Co-Authored-By: Claude Code AI
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add support for the optional `mode` argument to `blockchain.estimatefee`
which was added in protocol v1.6. The mode is passed to bitcoind's
`estimatesmartfee` RPC as the `estimate_mode` parameter.

- Add `EstimationMode` enum with `Conservative` and `Economical` variants
- Update `estimate_fee` to take `Option<EstimationMode>` as second parameter
- Update `Batch::estimate_fee` to support the mode parameter
- `batch_estimate_fee` currently always uses `None` for mode

This is a breaking change as the `estimate_fee` signature has changed.

Co-Authored-By: Claude Code AI
tnull added 4 commits January 28, 2026 10:14
…patibility

Parse `blockchain.block.headers` response based on negotiated protocol version:
- v1.6+: Headers returned as array of hex strings in `headers` field
- v1.4 (legacy): Headers returned as concatenated hex in `hex` field

- Add `is_protocol_version_at_least()` helper for semantic version comparison
- Rename old response type to `GetHeadersResLegacy` (internal)
- New `GetHeadersRes` handles v1.6 format with `header_hexes` field
- Both formats produce the same public `headers: Vec<block::Header>` output

Co-Authored-By: Claude Code AI
Add support for the `blockchain.transaction.broadcast_package` RPC method
introduced in protocol v1.6 for package relay (CPFP) support.

- Add `BroadcastPackageRes` and `BroadcastPackageError` types
- Add `Param::StringVec` variant for array parameters
- Add `transaction_broadcast_package_raw` trait method with generic `AsRef<[u8]>`
- Add `transaction_broadcast_package` convenience method that serializes transactions

Co-Authored-By: Claude Code AI
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add documentation note that `relay_fee` is deprecated in protocol v1.6
and users should use `mempool_get_info` instead.

Co-Authored-By: Claude Code AI
Previously we'd then fail on the deserialization step, which is odd.

Signed-off-by: Elias Rohrer <dev@tnull.de>
@tnull tnull force-pushed the 2026-01-protocol-v1.6 branch from 485c4b0 to a439485 Compare January 28, 2026 09:15
@tnull
Copy link
Contributor Author

tnull commented Jan 28, 2026

Addressed pending comments and force-pushed the following changes:

> git diff-tree -U2  485c4b0 a439485
diff --git a/src/raw_client.rs b/src/raw_client.rs
index d806a92..3feb754 100644
--- a/src/raw_client.rs
+++ b/src/raw_client.rs
@@ -47,5 +47,5 @@ use crate::types::*;

 /// Client name sent to the server during protocol version negotiation.
-pub const CLIENT_NAME: &str = "rust-electrum-client";
+pub const CLIENT_NAME: &str = "";

 /// Minimum protocol version supported by this client.
@@ -965,4 +965,5 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
                 deserialized.headers.push(deserialize(&header_bytes)?);
             }
+            deserialized.header_hexes.clear();
             Ok(deserialized)
         } else {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Add support for Electrum protocol v1.6

3 participants