Skip to content

Expose negotiated protocol version - #213

Merged
oleonardolima merged 1 commit into
bitcoindevkit:masterfrom
tnull:2026-06-expose-protocol-version
Jul 23, 2026
Merged

Expose negotiated protocol version#213
oleonardolima merged 1 commit into
bitcoindevkit:masterfrom
tnull:2026-06-expose-protocol-version

Conversation

@tnull

@tnull tnull commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

The v1.6 upgrade (#190) negotiates and stores the server's protocol version
during connection setup, but there was no public API to read it back.

This adds ElectrumApi::protocol_version():

  • RawClient returns the version negotiated at connection setup; if none was
    cached, it issues a single server.version call and caches the result
  • the trait provides a default implementation for implementors that don't
    cache, querying server.version directly
  • negotiate_protocol_version is split into request_server_version /
    cache_protocol_version helpers so the connection-setup and lazy paths
    share the same code

Notes to the reviewers

The tests introduce a MockStream test double that records written requests,
allowing protocol_version() to be verified offline: the negotiated value is
returned without an extra wire request, and the lazy path fetches exactly once
and caches (asserted via calls_made() and the captured requests).

Changelog notice

### Added

- Add `protocol_version()` to `ElectrumApi`, returning the protocol version
  negotiated during connection setup #213

Checklists

All Submissions:

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK f78ed74

Overall it looks good! I pushed a commit fixing the CI, though.

@caarloshenriq caarloshenriq left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

tACK fadedd9

I wrote this example to validate:

use electrum_client::{Client, Config, ElectrumApi, Socks5Config};
use std::env;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let url = env::args().nth(1).expect("uso: cargo run --example test_protocol_version -- <url> [socks5_addr]");
    let proxy = env::args().nth(2);

    let config = Config::builder()
        .validate_domain(false)
        .socks5(proxy.map(Socks5Config::new))
        .build();

    let client = Client::from_config(&url, config)?;
    println!("{} -> protocol_version = {}", url, client.protocol_version()?);

    let features = client.server_features()?;
    println!("server_features = {:#?}", features);

    Ok(())
}

and tested using these electrum url's

➜  rust-electrum-client git:(pr-213) - cargo run --example test_protocol_version -- "ssl://testnet.aranguren.org:51002"
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s
     Running `target/debug/examples/test_protocol_version 'ssl://testnet.aranguren.org:51002'`
ssl://testnet.aranguren.org:51002 -> protocol_version = 1.6
server_features = ServerFeaturesRes {
    server_version: "Fulcrum 2.1.1",
    genesis_hash: [
        0,
        0,
        0,
        0,
        9,
        51,
        234,
        1,
        173,
        14,
        233,
        132,
        32,
        151,
        121,
        186,
        174,
        195,
        206,
        217,
        15,
        163,
        244,
        8,
        113,
        149,
        38,
        248,
        215,
        127,
        73,
        67,
    ],
    protocol_min: "1.4",
    protocol_max: "1.6",
    hash_function: Some(
        "sha256",
    ),
    pruning: None,
}
➜  rust-electrum-client git:(pr-213) - cargo run --example test_protocol_version -- "tcp://blackie.c3-soft.com:57005"
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
     Running `target/debug/examples/test_protocol_version 'tcp://blackie.c3-soft.com:57005'`
tcp://blackie.c3-soft.com:57005 -> protocol_version = 1.6
server_features = ServerFeaturesRes {
    server_version: "Fulcrum 2.1.1",
    genesis_hash: [
        0,
        0,
        0,
        0,
        9,
        51,
        234,
        1,
        173,
        14,
        233,
        132,
        32,
        151,
        121,
        186,
        174,
        195,
        206,
        217,
        15,
        163,
        244,
        8,
        113,
        149,
        38,
        248,
        215,
        127,
        73,
        67,
    ],
    protocol_min: "1.4",
    protocol_max: "1.6",
    hash_function: Some(
        "sha256",
    ),
    pruning: None,
}
➜  rust-electrum-client git:(pr-213) - cargo run --example test_protocol_version -- "ssl://blackie.c3-soft.com:62002"
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s
     Running `target/debug/examples/test_protocol_version 'ssl://blackie.c3-soft.com:62002'`
ssl://blackie.c3-soft.com:62002 -> protocol_version = 1.6
server_features = ServerFeaturesRes {
    server_version: "Fulcrum 2.1.1",
    genesis_hash: [
        0,
        0,
        0,
        0,
        29,
        212,
        16,
        196,
        154,
        120,
        134,
        104,
        206,
        38,
        117,
        23,
        24,
        204,
        121,
        116,
        116,
        211,
        21,
        42,
        95,
        192,
        115,
        221,
        68,
        253,
        159,
        123,
    ],
    protocol_min: "1.4",
    protocol_max: "1.6",
    hash_function: Some(
        "sha256",
    ),
    pruning: None,
}

➜  rust-electrum-client git:(pr-213) - cargo run --example test_protocol_version -- "tcp://5dfr3ossuq3kxyc4zsgwqarh37yzlp7b6jc2j7h2gjq6jp7d7zg6fnid.onion:62001" "127.0.0.1:9050"
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/examples/test_protocol_version 'tcp://5dfr3ossuq3kxyc4zsgwqarh37yzlp7b6jc2j7h2gjq6jp7d7zg6fnid.onion:62001' '127.0.0.1:9050'`
tcp://5dfr3ossuq3kxyc4zsgwqarh37yzlp7b6jc2j7h2gjq6jp7d7zg6fnid.onion:62001 -> protocol_version = 1.6
server_features = ServerFeaturesRes {
    server_version: "Fulcrum 2.1.0",
    genesis_hash: [
        0,
        0,
        0,
        0,
        29,
        212,
        16,
        196,
        154,
        120,
        134,
        104,
        206,
        38,
        117,
        23,
        24,
        204,
        121,
        116,
        116,
        211,
        21,
        42,
        95,
        192,
        115,
        221,
        68,
        253,
        159,
        123,
    ],
    protocol_min: "1.4",
    protocol_max: "1.6",
    hash_function: Some(
        "sha256",
    ),
    pruning: None,
}

@oleonardolima
oleonardolima force-pushed the 2026-06-expose-protocol-version branch from f78ed74 to 522ffc1 Compare July 22, 2026 18:56
@oleonardolima

Copy link
Copy Markdown
Collaborator

@caarloshenriq did you manage to test it against a server that didn't support v1.6 ?

@oleonardolima
oleonardolima force-pushed the 2026-06-expose-protocol-version branch from 522ffc1 to 582c80f Compare July 22, 2026 19:12

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK 582c80f

@caarloshenriq

Copy link
Copy Markdown

@caarloshenriq did you manage to test it against a server that didn't support v1.6 ?

yes, I tested with two servers: b.1209k.com:50002 and 18.195.224.155:50002 runs Fulcrum 1.11.1

Confirmed via server_features() that protocol_max is 1.5.3, and protocol_version() correctly negotiates down:

➜  rust-electrum-client: cargo run --example test_protocol_version -- "ssl://b.1209k.com:50002"
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
     Running `target/debug/examples/test_protocol_version 'ssl://b.1209k.com:50002'`
ssl://b.1209k.com:50002 -> protocol_version = 1.5.3
server_features = ServerFeaturesRes {
    server_version: "Fulcrum 1.11.1",
    genesis_hash: [
        0,
        0,
        0,
        0,
        0,
        25,
        214,
        104,
        ...
    ],
    protocol_min: "1.4",
    protocol_max: "1.5.3",
    hash_function: Some(
        "sha256",
    ),
    pruning: None,
}

➜  rust-electrum-client: cargo run --example test_protocol_version -- "ssl://18.195.224.155:50002"
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
     Running `target/debug/examples/test_protocol_version 'ssl://18.195.224.155:50002'`
ssl://18.195.224.155:50002 -> protocol_version = 1.5.3
server_features = ServerFeaturesRes {
    server_version: "Fulcrum 1.11.1",
    genesis_hash: [
        0,
        0,
        0,
        0,
        0,
        25,
        214,
        104,
        ...
    ],
    protocol_min: "1.4",
    protocol_max: "1.5.3",
    hash_function: Some(
        "sha256",
    ),
    pruning: None,
}

The v1.6 upgrade negotiated and stored the server protocol
version during connection setup, but omitted the documented
public API for reading it.

Add protocol_version() so callers can reuse the negotiated value.
Only fall back to server.version when no cached version exists.

Co-Authored-By: HAL 9000
@oleonardolima
oleonardolima force-pushed the 2026-06-expose-protocol-version branch from 582c80f to 70d51de Compare July 23, 2026 16:17

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ACK 70d51de

@oleonardolima
oleonardolima merged commit e1be8d9 into bitcoindevkit:master Jul 23, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this from Needs Review to Done in BDK Chain Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants