Skip to content

bitcoin_core_sv2 supports multiple versions of Bitcoin Core (v30.x + v31.x)#548

Open
plebhash wants to merge 13 commits into
stratum-mining:mainfrom
plebhash:2026-05-27-bitcoin-core-sv2-multi-version
Open

bitcoin_core_sv2 supports multiple versions of Bitcoin Core (v30.x + v31.x)#548
plebhash wants to merge 13 commits into
stratum-mining:mainfrom
plebhash:2026-05-27-bitcoin-core-sv2-multi-version

Conversation

@plebhash

@plebhash plebhash commented Jun 8, 2026

Copy link
Copy Markdown
Member

close #516


in summary:

  • bitcoin_core_sv2 now supports both Bitcoin Core IPC v30.x and v31.x via one common API with versioned backends.
  • template_provider_type.BitcoinCoreIpc.version is now required (30 or 31) and wired through Pool/JDC/JDS runtime selection.
  • Added focused integration coverage for both versions in new IPC IO tests (JDP + TDP).
  • Docker config is now version-configurable via:
    • POOL_BITCOIN_CORE_IPC_VERSION
    • JDC_BITCOIN_CORE_IPC_VERSION

note: should be merged after #545

@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch 20 times, most recently from 14a8b80 to c3bf3b1 Compare June 9, 2026 01:20
@Shourya742 Shourya742 self-requested a review June 9, 2026 16:52
@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch 4 times, most recently from df3ce2a to 9a17e32 Compare June 9, 2026 20:25
@plebhash plebhash marked this pull request as ready for review June 9, 2026 20:26
@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch from 9a17e32 to d757e22 Compare June 9, 2026 21:13
Comment thread bitcoin-core-sv2/src/common/mod.rs Outdated
Comment thread bitcoin-core-sv2/src/common/mod.rs Outdated
Comment thread bitcoin-core-sv2/src/unix_capnp/v30x/job_declaration_protocol/handlers.rs Outdated
Comment thread miner-apps/jd-client/src/lib/mod.rs Outdated
Comment thread stratum-apps/src/tp_type.rs Outdated
@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch from d757e22 to e0f2a39 Compare June 17, 2026 16:06
@plebhash

plebhash commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

Why didn't we get CI failures on #553 though?

I asked gpt-5.3-codex a similar question earlier:

Great question. Short answer: PR #573 was close, but still below the runner disk limit; PR #548 crossed it.

What’s different:

So this is mostly a capacity threshold + branch footprint issue, not a “new code error.”

IIUC this PR is already increasing the build artifact footprint due to:

  • multiple capnp + capnp-rpc crate versions on the dependency list
  • more source code

then #553 increased it further with the addition of asic-rs

and now the combination of both started pushing the github runners over the limit

@plebhash

plebhash commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

also getting similar disk-out-of-space errors after merging #531:

so maybe f4a88f8 is not enough, and we might continue to get flaky PITA over this.... let's see

Comment thread .github/workflows/msrv.yaml Outdated
Comment thread .github/workflows/msrv.yaml Outdated
Comment thread .github/workflows/msrv.yaml Outdated

@GitGab19 GitGab19 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Besides of my last comments, which are only about the msrv.yaml workflow changes, I just tested with both v30.2 and v31, and everything worked fine!

tACK

@Shourya742 Shourya742 self-requested a review June 19, 2026 10:03
@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch 3 times, most recently from a721748 to 61d1eaf Compare June 19, 2026 13:50

@Shourya742 Shourya742 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some suggestions and questions


- name: Check test compilation for jd-server
run: cargo test --manifest-path=pool-apps/jd-server/Cargo.toml --no-run

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this makes sense, can you do the same in ci,yaml and lockfile.yaml

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done

Comment thread pool-apps/pool/src/lib/mod.rs Outdated

let bitcoin_core_cancellation_token = CancellationToken::new();
let bitcoin_core_config = BitcoinCoreSv2TDPConfig {
version: version.to_bitcoin_core_version(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why we have two different versioning shouldn't they be the same?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I also don't love the duplication of stratum-apps::tp_type::BitcoinCoreIpcVersion vs bitcoin_core_sv2::common::BitcoinCoreVersion

we can get rid of stratum-apps::tp_type::BitcoinCoreIpcVersion in favor of bitcoin_core_sv2::common::BitcoinCoreVersion, but with the tradeoff of having stratum-apps::tp_type::TemplateProviderType::BitcoinCoreIpc variant behind bitcoin-core-sv2 feature gate

tbh, that feels like a reasonable tradeoff, implementing it

Comment thread stratum-apps/src/tp_type.rs Outdated
Comment on lines +30 to +34
#[cfg(feature = "bitcoin-core-sv2")]
pub fn to_bitcoin_core_version(self) -> bitcoin_core_sv2::common::BitcoinCoreVersion {
bitcoin_core_sv2::common::BitcoinCoreVersion::try_from(self.as_major())
.expect("BitcoinCoreIpcVersion and BitcoinCoreVersion majors must stay aligned")
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this be a from instead of try_from, considering we already converted from config to BitcoinCoreIpcVersion enum and after than any conversion should be lossless.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

based on the adaptations from #548 (comment), this is no longer relevant

Comment thread stratum-apps/src/tp_type.rs Outdated
}
}

impl TryFrom<u16> for BitcoinCoreIpcVersion {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this be u8?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

based on the adaptations from #548 (comment), this is no longer relevant

Comment on lines +24 to +33
#[async_trait::async_trait(?Send)]
pub trait Sv2TemplateDistributionProtocol {
async fn run(&mut self);
}

/// Version-agnostic TDP runtime handle.
///
/// Instances are created with [`new`], which selects the concrete backend for the requested
/// [`BitcoinCoreVersion`].
pub type BitcoinCoreSv2TDP = Box<dyn Sv2TemplateDistributionProtocol>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can model it via enums having a common interface, something like this:

pub enum BitcoinCoreSv2TDP {
    V30X(v30x::template_distribution_protocol::BitcoinCoreSv2TDP),
    V31X(v31x::template_distribution_protocol::BitcoinCoreSv2TDP),
}

impl BitcoinCoreSv2TDP {
    pub async fn run(&mut self) {
        match self {
            Self::V30X(runtime) => runtime.run().await,
            Self::V31X(runtime) => runtime.run().await,
        }
    }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would help in removal of async_trait and vtable lookup

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

when I originally wrote the scope of #516 I explicitly mentioned the introduction of traits on the common module, which would serve the purpose of establishing clear interfaces for which all different version implementations would follow

but the implementation converged towards a very thin trait interface (limited to a single run method), which honestly makes it not so much valuable anymore

I think this suggestion makes sense, since we'd still be following the same run pattern, while enforcing it inside the match

so yeah thanks for the suggestion @Shourya742 implementing it

async fn run(&mut self) {
BitcoinCoreSv2TDP::run(self).await;
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can removed with enum dispatch.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done

Comment on lines +24 to +33
#[async_trait::async_trait(?Send)]
pub trait Sv2JobDeclarationProtocol {
async fn run(&self);
}

/// Version-agnostic JDP runtime handle.
///
/// Instances are created with [`new`], which selects the concrete backend for the requested
/// [`BitcoinCoreVersion`].
pub type BitcoinCoreSv2JDP = Box<dyn Sv2JobDeclarationProtocol>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The enum variant for this can be very similar?

pub enum BitcoinCoreSv2JDP {
    V30X(v30x::job_declaration_protocol::BitcoinCoreSv2JDP),
    V31X(v31x::job_declaration_protocol::BitcoinCoreSv2JDP),
}

impl BitcoinCoreSv2JDP {
    pub async fn run(&self) {
        match self {
            Self::V30X(runtime) => runtime.run().await,
            Self::V31X(runtime) => runtime.run().await,
        }
    }
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done

Comment on lines +35 to +52
#[derive(Debug)]
pub struct BitcoinCoreSv2JDPError {
version: BitcoinCoreVersion,
details: String,
}

impl fmt::Display for BitcoinCoreSv2JDPError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"failed to initialize bitcoin_core_sv2 JDP for v{}: {}",
self.version.as_major(),
self.details
)
}
}

impl std::error::Error for BitcoinCoreSv2JDPError {}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can abstract it out with common Error from common module

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done

Comment on lines +13 to +20
impl BitcoinCoreVersion {
pub const fn as_major(self) -> u8 {
match self {
Self::V30X => 30,
Self::V31X => 31,
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe the new methods can become part of the version fields itself, instead of us having to pass version in the new constructor:

    pub async fn new_jdp<P>(
        self,
        bitcoin_core_unix_socket_path: P,
        incoming_requests: async_channel::Receiver<job_declaration_protocol::io::JdRequest>,
        cancellation_token: tokio_util::sync::CancellationToken,
        ready_tx: tokio::sync::oneshot::Sender<()>,
    ) -> Result<job_declaration_protocol::BitcoinCoreSv2JDP, BitcoinCoreSv2Error>
    where
        P: AsRef<std::path::Path>,
    {
        ...
    }

    /// Builds a TDP runtime for this Bitcoin Core IPC schema family.
    #[allow(clippy::too_many_arguments)]
    pub async fn new_tdp<P>(
        self,
        bitcoin_core_unix_socket_path: P,
        fee_threshold: u64,
        min_interval: u8,
        incoming_messages: async_channel::Receiver<
            stratum_core::parsers_sv2::TemplateDistribution<'static>,
        >,
        outgoing_messages: async_channel::Sender<
            stratum_core::parsers_sv2::TemplateDistribution<'static>,
        >,
        global_cancellation_token: tokio_util::sync::CancellationToken,
    ) -> Result<template_distribution_protocol::BitcoinCoreSv2TDP, BitcoinCoreSv2Error>
    where
        P: AsRef<std::path::Path>,
    {
       ...
    }

specific version association attached to version itself.

@plebhash plebhash Jun 22, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I experimented with this but I didn't like the result... adding a new_jdp/new_tdp constructors to BitcoinCoreVersion feels like we're mixing abstractions

keeping as-is

@@ -0,0 +1,126 @@
//! Local mempool mirror for Bitcoin Core v31.x Sv2 Job Declaration Protocol via capnp over UNIX

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we move the common module at the same level as versioning module?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think its the same file as v30x?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

that's similar to what's already been discussed here: #548 (comment)

Can we move the common module at the same level as versioning module?

tbh if we were to do this, we should apply the same pattern across the entire crate, which is the scope of #574

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I just read the issue, with the current structuring it won't be easy for us to remove duplication. I am now thinking whether it will be viable to have version based distinct implementation, like in a method, based on version we can have different implementation (via match). What you think of this?

@plebhash plebhash Jun 22, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

when I discussed this with @GitGab19 the consensus was to leave code de-duplication as something to be solved later.

I also don't fully understand what you're trying to say on the comment above.

with the current structuring it won't be easy for us to remove duplication.

by "current structuring" do you mean what is being done on this PR or what's proposed on #574?

I am now thinking whether it will be viable to have version based distinct implementation, like in a method, based on version we can have different implementation (via match). What you think of this?

assuming this suggestion is meant to be taken as an alternative approach to #574, I first need to understand what you understand as a problem with what was proposed there

and also, do you think this is something that needs to be addressed now?

if not, we should discuss it under #574 and not here

@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch 2 times, most recently from 798d191 to c89290e Compare June 22, 2026 22:31
@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch from c89290e to 91a3d9e Compare June 22, 2026 22:31
@plebhash plebhash force-pushed the 2026-05-27-bitcoin-core-sv2-multi-version branch from 868fd8a to c9ea2b7 Compare June 22, 2026 23:36
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.

bitcoin_core_sv2 must simultaneously support Bitcoin Core v30.x + v31.x

3 participants