Skip to content

Add Stratum V2 (SV2) protocol support#1553

Draft
warioishere wants to merge 18 commits intobitaxeorg:masterfrom
warioishere:feature/stratum-v2-support
Draft

Add Stratum V2 (SV2) protocol support#1553
warioishere wants to merge 18 commits intobitaxeorg:masterfrom
warioishere:feature/stratum-v2-support

Conversation

@warioishere
Copy link

@warioishere warioishere commented Feb 14, 2026

Summary

Adds Stratum V2 binary protocol support alongside the existing V1 JSON-RPC implementation. Tested on a BM1370 bitaxe against a local SRI server and the SRI reference pool — full 1.3 TH/s hashrate with shares accepted.

What's included:

  • SV2 binary protocol: frame encoding/decoding, mining channel messages (SetupConnection, OpenStandardMiningChannel, NewMiningJob, SetNewPrevHash, SetTarget, SubmitSharesStandard)
  • SV2 Noise encryption: Noise_NX handshake with ChaCha20-Poly1305 transport via libsecp256k1 (git submodule v0.6.0)
  • Protocol coordinator with separate V1/V2 task files and fallback/recovery logic
  • Protocol selectable via NVS config and AxeOS Pool Settings UI (both primary and fallback pool)

What works:

  • Full hashrate (1.3 TH/s on BM1370)
  • Encrypted connection via Noise protocol
  • Share submission and acceptance
  • Pool difficulty tracking via SetTarget
  • V1/V2 protocol switching and fallback

Open decisions

none

Test plan

  • SV2 connection + Noise handshake against SRI server
  • Full hashrate (1.3 TH/s) with BM1370
  • Shares accepted, no duplicates
  • Dashboard loads in SV2 mode
  • V1 mode unaffected
  • Tested against SRI reference pool
  • Test on other ASIC variants (BM1366, BM1368, BM1397)

Test servers

Public SV2 test server:

  • Host: blitzpool-test.yourdevice.ch
  • Port: 3333
  • Authority Public Key: 9bCoFxTszKCuffyywH5uS5o6WcU4vsjTH2axxc7wE86y2HhvULU
  • running on regtest

SRI reference pool (confirmed working):

  • Host: 75.119.150.111
  • Port: 3333
  • Authority Public Key: 9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72

For transparency: most of this implementation was done with the help of Claude (Opus 4.6). I hope that doesn't detract from the goal of bringing SV2 support to bitaxe.

@warioishere warioishere force-pushed the feature/stratum-v2-support branch from 8882a06 to 9551b7e Compare February 15, 2026 07:58
@mutatrum
Copy link
Collaborator

Please add some screenshots.

I've had a cursory look at the code, will do a more in-depth review later. I'm not opposed to agentic development, however, only if the author is familiar with the codebase and does first line code reviews as well. This codebase looks decent, but I did see some areas where it could benefit more from separation of concerns.

For example: would it be cleaner to have a dedicated stratum_v2_task.c, instead of intermingling the two protocols in stratum_task.c? This holds for all touch-points of sv2, try to make it as clean as possible, with the least amount of if sv else sv2 statements sprinkled throughout the code.

If you have Claude work on it, please make it aware of #901, and have it keep that in mind that if we're splitting off work production protocols, this is something that I might like to add as well in the future.

@warioishere
Copy link
Author

warioishere commented Feb 15, 2026

Please add some screenshots.

I've had a cursory look at the code, will do a more in-depth review later. I'm not opposed to agentic development, however, only if the author is familiar with the codebase and does first line code reviews as well. This codebase looks decent, but I did see some areas where it could benefit more from separation of concerns.

For example: would it be cleaner to have a dedicated stratum_v2_task.c, instead of intermingling the two protocols in stratum_task.c? This holds for all touch-points of sv2, try to make it as clean as possible, with the least amount of if sv else sv2 statements sprinkled throughout the code.

If you have Claude work on it, please make it aware of #901, and have it keep that in mind that if we're splitting off work production protocols, this is something that I might like to add as well in the future.

Hey, I'll refactor this using a protocol coordinator pattern. I'll extract V1 into its own task (stratum_v1_task), remove the cross-protocol dependencies from sv2_task,
and add some helper functions for the shared operations like share submission. The coordinator will handle all the fallback/recovery logic instead of having tasks create each other.

I'm keeping create_jobs_task unified since it already works fine, and I don't think the global_state union or vtable stuff is worth the complexity. I'll remove the old stratum_task.c once everything tests out.

I read #901 already, but I thought about usings sv2 capability to connect to a separate jd-client that can connect to bitcoin core via Sjors TP, that would give us also full control over templates and dezentralize things further, but yea, I can have a look onto this option directly getting templates from core as its far simplier then using a jd-client.

We can look at this in further developement, okay?

@mutatrum
Copy link
Collaborator

mutatrum commented Feb 15, 2026

GetBlockTemplate mining is definitely for another PR, this is already quite big.

Some more code review remarks:

  • sv2_api.h filename mismatches sv2_protocol.c;
  • How much effort is it to support NewExtendedMiningJob so coinbase_decoder can be hooked up?
  • Not sure if the way the config works makes sense now:
    image The connection security radiobox is mutually exclusive with the protocol options, as is the sv2 Pool Fingerprint. It would make more sense to first have the Protocol option, and make the sv1/sv2 options only visible for the selected protocol. E.g. only show Connection Security on SV1, only show Pool Fingerprint on SV2;
  • Primary and secondary pool should both have the sv2 option. Not sure how the liveliness check on the primary pool should work with sv2?
  • Make naming a bit more consistent: sv2_task is unclear, which task is it? The current naming is not perfect either, but at least it shouldn't be made more confusing :-)

On libsecp256k1:

  • With the submodule, does the project checkout change now? And how does this transition for people already having checked out the project?
  • How is the version of the dependency managed?
  • Both questions might need stuff in the readme added.

@warioishere
Copy link
Author

warioishere commented Feb 16, 2026

New clones need git clone --recursive, and existing checkouts need a one-time git submodule update --init --recursive after pulling, otherwise the build fails on an empty directory.

The submodule is pinned to commit 0cdc758 (tagged v0.6.0 of bitcoin-core/secp256k1). Git tracks the exact commit hash, so everyone gets the same version. Updating means checking out a new tag in the submodule dir and committing the pointer change. I will add this to the README.

I'd love to see extended channel support as well, but I think it makes sense to handle it in a separate PR. For now, let's prioritize standard channels here.

Standard channels have a clear advantage for a device like the BitAxe: the network overhead is minimal since the pool precomputes everything and the miner only receives the block header. Extended channels would require handling the full coinbase transaction on the miner side, which adds complexity here now to review and test.

Once standard channels are solid, we can build on that foundation and add extended channel support with coinbase TX handling in a follow-up PR.

Will keep the sv2_api.h filename mismatches sv2_protocol.c in mind during refactoring now and also consider a better naming.

Currently, we only have options based on what Protocol we choose so users dont get confused:

grafik

and for Sv2

grafik

I have also added Sv2 Mode for Fallback Pool.

grafik

Would you like to have everything in a single commit after refactoring? Should be done by this evening.

@warioishere warioishere force-pushed the feature/stratum-v2-support branch from 9551b7e to 0470129 Compare February 16, 2026 16:35
@warioishere
Copy link
Author

Refactoring is done, everything squashed into a single commit.

Here's what changed since last time: V1 and V2 now live in their own task files (stratum_v1_task.c and stratum_v2_task.c), with a protocol coordinator handling all the fallback and recovery logic. The old stratum_task.c is gone. Fixed the sv2_api.h naming mismatch, it's consistently sv2_protocol now.

Both primary and fallback pool support SV2 selection, and the UI only shows relevant options per protocol. Heartbeat probing works for both V1 and V2 primaries, so liveness checks are covered regardless of protocol combo.

Also fixed a bunch of stability issues with protocol switching - the old implementation would crash or restart the device when switching between V1 and V2 at runtime. That's sorted now.

Extended channel support and GetBlockTemplate mining are left for follow-up PRs as discussed.

Ready for review 🚀

@mutatrum
Copy link
Collaborator

No need to do squash and force-push. This makes it harder to review incremental changes.

@warioishere
Copy link
Author

i made a backup of the branch before squashing, should I revert?

@mutatrum
Copy link
Collaborator

i made a backup of the branch before squashing, should I revert?

No it's fine for this PR. Sometime a squash and/or force push is necessary to fix merges, so no problem. Just for future reference, the code will be squashed into a single commit on merge anyways.

@mutatrum
Copy link
Collaborator

Can you see if you can update your branch, it looks like some changes that were added to master have been added here as well. These might drop out if you update.

@warioishere warioishere force-pushed the feature/stratum-v2-support branch from 0470129 to b3d3a46 Compare February 16, 2026 18:37
@warioishere
Copy link
Author

Can you see if you can update your branch, it looks like some changes that were added to master have been added here as well. These might drop out if you update.

Updated the branch, rebased onto latest master. The 3 duplicate commits dropped out. Should be a cleaner diff now.

Add full Stratum V2 mining protocol support to the bitaxe, enabling
encrypted communication with SV2 pools via Noise_NX handshake
(secp256k1+EllSwift, ChaChaPoly, SHA256). Includes a robust
protocol coordinator for clean failover between any combination
of V1/V2 primary and fallback pools without device restarts.

Protocol implementation:
- SV2 binary protocol (components/stratum_v2/): SetupConnection,
  OpenStandardMiningChannel, NewMiningJob, SetNewPrevHash, SetTarget,
  SubmitShares with proper frame encoding/decoding
- Noise encryption (sv2_noise.c): Full NX handshake with optional
  authority public key verification (TOFU mode when unconfigured)
- libsecp256k1 v0.6.0 as git submodule for elliptic curve operations

Protocol coordinator and fallback:
- Non-blocking event-driven coordinator manages protocol task lifecycle
- Supports all 4 failover combinations: V2->V1, V2->V2, V1->V2, V1->V1
- Timer-based heartbeat probes primary pool during fallback operation
- User-selected fallback (dashboard toggle) disables auto-recovery
- Clean state transitions: queue clear, share stats reset, proper
  task shutdown with event synchronization

Key reliability fixes:
- Heap-allocate sv2_conn to prevent dangling pointer after task exit
- Dynamic protocol check in create_jobs_task (was cached at startup,
  causing memory corruption on protocol switch)
- Single event per task exit (was double-signaling coordinator)
- Remove esp_restart() from V1 task, notify coordinator instead
- Fix V1 transport handle leak (destroy after close)
- Remove close_connection race from asic_result_task

Frontend and configuration:
- NVS settings for SV2 authority pubkey and fallback pool protocol
- Pool settings UI: protocol selector and SV2 pubkey for both pools,
  V1-only options hidden when SV2 selected
- Display: hide block height and scriptsig in SV2 mode (not available
  in standard channel), show protocol indicator instead
- OpenAPI spec updated with new SV2 configuration fields
@warioishere warioishere force-pushed the feature/stratum-v2-support branch from b3d3a46 to 51787d9 Compare February 16, 2026 18:40
coordinator_state_t and coordinator_event_t are only used inside
protocol_coordinator.c, no need to expose them in the header.
@jbesraa
Copy link

jbesraa commented Feb 17, 2026

Which parts of SV2 protocol does this implement, is it Mining protocol or JD as well? Does it include both extended and standard channels support?
Would be nice if you could provide instructions on how to test this with my bitaxe.

@warioishere
Copy link
Author

warioishere commented Feb 17, 2026

currently no extented channels, that will be part of a next PR. and no JD-client, but I am building an easy to setup full stack deployment which you could run on a raspberry pi, or even on the node itself. Contains a JD-Client, TP from Sjor, and a bitcoincore setup build with --enable-multiprocess so that the IPC Unix socket connection method can be used:

https://github.com/warioishere/sv2-apps

@warioishere
Copy link
Author

warioishere commented Feb 17, 2026

jst confirmed the implementation works also againstthe original sv2 reference server:

authority_pubkey = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72" 
pool_address = "75.119.150.111" 
pool_port = 3333 

@mutatrum
Copy link
Collaborator

Do you have a Max (BM1397) device to test against? The others are functionally equivalent with respect to job construction/asic comms.

@plebhash
Copy link

ntime rolling for ASIC work generation

ntime rolling on a bitaxe seems quite backwards?

@plebhash
Copy link

plebhash commented Feb 17, 2026

elaborating on the comment above

IIUC the BM1370 doesn't support version rolling, which is forcing you to roll ntime so you can stick with a standard channel, right?

This is explicitly allowed by the SV2 spec.

"allowed" but not definitely not encouraged... rolling ntime can have bad consequences on consensus level

as a rule of thumb, ntime should only be increased when we want to reset the search space and we know we've been hashing for longer than 1s

and it should happen like this:

  • increment 1 unit on ntime, hash for at least 1s
  • increment 1 unit on ntime, hash for at least 1s
  • ...

or at least some variation that respects ntime as something that progresses together with real time, and not something that rolls indefinitely into the past or future (with undesired consequences)


overall, I think it's a very good idea to support Sv2 Standard Channels as a "first class citizen" on AxeOS

but for edge cases where ASICs cannot do version rolling, I would go with Extended Channels and not try to reinvent the wheel

@warioishere
Copy link
Author

warioishere commented Feb 17, 2026

IIUC the BM1370 doesn't support version rolling

Can you elaborate on this? From what I see in the codebase, the BM1370 does do hardware version rolling:

  • BM1370_set_version_mask() writes the mask to register 0xA4 on the chip, and it's called during init with 0x1fffe000
  • The ASIC result struct includes a 16-bit version field that gets shifted left 13 (version_bits = ntohs(asic_result.job.version) << 13), matching the mask exactly
  • The rolled version is reconstructed via OR: version | version_bits

These are latest-gen Antminer S21 chips — would be surprising if they dropped version rolling support. The BM1397 is the only one where set_version_mask is a no-op placeholder.

That said, you're right that the ntime rolling approach is wrong regardless. Even if the ASIC does version roll, bumping ntime by +1 every 500ms job send is not how ntime should be used. I'll fix that — either remove the offset entirely (since version rolling gives enough search space) or clamp it to real elapsed wall-clock time.

What would you suggest as the right approach here for standard channels?

@warioishere
Copy link
Author

Do you have a Max (BM1397) device to test against? The others are functionally equivalent with respect to job construction/asic comms.

the BM1397 is the only ASIC where set_version_mask is a no-op — it doesn't do hardware version rolling. That means SV2 standard channels won't give it enough search space even with jst ntime rolling, which isn't a good solution (see discussion with plebhash above).

I think there are two options here:

  1. Exclude the BM1397 from SV2 support in this PR entirely, and only enable it later when we add extended channel support
  2. Drop SV2 support for the Bitaxe Max altogether, given it's the oldest generation

What do you think makes more sense?

@mutatrum
Copy link
Collaborator

Excluding a chip from a protocol is a bit of a nasty dependency. Maybe adding Extended channels also puts it more in line with how SV1 currently works. I can't really oversee how much more work that is to support though.

@warioishere
Copy link
Author

Yeah, I agree excluding a chip entirely from a protocol isn't great. I think the clean approach is:

  • BM1397 can't do hardware version rolling, so standard channels don't give it enough search space
  • BM1366/BM1368/BM1370 all have working version rolling, so standard channels work fine

The channel type decision is just a runtime check on the ASIC ID — use OpenExtendedMiningChannel for BM1397, OpenStandardMiningChannel for the rest. That way the BM1397 gets an extranonce to vary (like SV1 today), and the others get the simpler standard channel path.

For this PR I'd scope it to standard channels only, which means BM1397 stays on SV1 for now. Extended channel support in a follow-up PR would unlock SV2 for the Max as well.

@warioishere
Copy link
Author

warioishere commented Feb 17, 2026

I looked into the effort for Extended Channel support. The good news is most of the heavy lifting already exists — calculate_coinbase_tx_hash() and calculate_merkle_root_hash() from the SV1 path do exactly what Extended Channels need (coinbase prefix + extranonce + suffix → merkle root). It's roughly ~700-800 lines of new code across 6 files, mainly new message parsers/builders in sv2_protocol.c and a generate_work_sv2_extended() that reuses the SV1 merkle computation.

One option would be to drop Standard Channels entirely and go straight to Extended Channels. That way:

  • All ASICs are supported (including BM1397/Max)
  • No ntime rolling needed — extranonce variation gives unlimited search space
  • Closer to how SV1 works today, so less conceptual difference
  • No need for channel-type branching logic

The tradeoff is that Extended Channels put more work on the miner (coinbase + merkle computation), but the ESP32 already does this for SV1 without issues.

What would you suggest — Extended-only, or keep both with a runtime ASIC check? Thats about a week more effort or so.

@plebhash
Copy link

IIUC the BM1370 doesn't support version rolling

Can you elaborate on this? From what I see in the codebase, the BM1370 does do hardware version rolling:

I'm not claiming this is true and I don't know whether BM1370 can do version rolling or not. I just got this understanding from the PR description.

The solution: Instead of rolling the version (which breaks BM1370's OR-based version reconstruction when carry transitions flip bits), we roll ntime on each work send. ntime is in the 2nd SHA-256 block (bytes 68-71), not in the midstate (bytes 0-63), so different ntime values produce unique hashes while midstates and the base version stay constant. This is explicitly allowed by the SV2 spec.

Add activeProtocolLabel field to /api/system/info endpoint that returns
the human-readable protocol string based on runtime state. Frontend now
just reads the backend-provided label.
Replace protocol/channel type logic with a simple blockHeight > 0 check.
The backend only populates coinbase fields when it has the data, so the
frontend just needs to check if the data is present.
sv2AuthorityPubkey → stratumV2AuthorityPubkey
sv2ChannelType → stratumV2ChannelType
fallbackSv2AuthorityPubkey → fallbackStratumV2AuthorityPubkey
fallbackSv2ChannelType → fallbackStratumV2ChannelType

Updated across NVS rest_name, http_server JSON, openapi.yaml, and
frontend components. NVS storage keys unchanged (no flash migration).
@warioishere
Copy link
Author

Thanks for the thorough review! Addressing your three key points:

1. Protocol separation / coordinator leakage:
The stop_v1_task/stop_v2_task functions manage coordinator-internal state (the event queue and shutdown flags) — moving them into the protocol tasks would leak the coordinator's internals into v1/v2. The heartbeat probes are similarly coordinator policy (deciding when to switch back to primary), not protocol logic per se.

That said, I agree the protocol-specific details in heartbeat_probe_v1 (subscribe/authorize) feel like leakage. One approach would be to expose a stratum_v1_probe(url, port, ...) function from v1_task that encapsulates the protocol handshake, and have the coordinator just call it. Same for v2 if the probe grows beyond a TCP connect. Would that address the concern, or do you see a bigger refactor here?

2. Unified job struct:
I agree in principle — the three job structs (mining_notify, sv2_job_t, sv2_ext_job_t) share most fields (version, prev_hash, ntime, nbits, clean_jobs, job_id). A unified struct with a protocol discriminator and a union for the protocol-specific parts (V1 hex coinbase strings vs V2 binary merkle root vs V2 extended coinbase prefix/suffix + merkle path) would reduce the dispatch branching in create_jobs_task.c.

The main friction is that V1 uses hex strings throughout (coinbase_1/2, prev_block_hash as char*) while V2 uses raw binary. Unifying would mean either converting V1 to binary at parse time or carrying both representations. I'd rather tackle this as a follow-up refactor once the SV2 protocol logic is stable and tested, rather than risk introducing bugs in the job pipeline in this PR. Would that be ok?

3. Unrelated changes:
Checked — the 4 PRs that show up in the diff (#1547, #1550, #1545, #1501) are all already merged to master. They appear because this branch was created before those merges. A rebase will clean them out, planning to do that once the review settles.

The work loop re-sends the current job to the ASIC on timeout.
For V1/SV2-extended this produces unique work (extranonce_2 changes),
but for SV2 standard channel the data is identical, restarting the
ASIC nonce search from 0 and producing duplicate shares.

Skip the re-send for SV2 standard channel. Once PR bitaxeorg#420 (fullscan
nonce space) is merged, the ASIC will have enough search space
(2^32 nonces x 2^16 version rolls) to keep mining without re-feeding.
@mutatrum
Copy link
Collaborator

mutatrum commented Mar 3, 2026

Thanks for the thorough review! Addressing your three key points:
[...]

To cover all comments: I think these issues can be done in a follow-up. There's something to say to leave the SV1 path as intact as possible, and only rework/integrate/unify stuff when the SV2 implementation is somewhat battle-tested.

mutatrum added a commit to mutatrum/ESP-Miner that referenced this pull request Mar 3, 2026
Author: wario_is_here <mario.hofmann@yourdevice.ch>
- Set poolConnectionInfo on all SV2 error paths with user-friendly
  messages (e.g. "Pool unreachable", "Auth failed - check key")
- Replace manual byte parsing of certificate with packed struct
Handle return values of secp256k1_context_randomize and
secp256k1_xonly_pubkey_from_pubkey to fix warn_unused_result warnings.
@sinnx3
Copy link

sinnx3 commented Mar 4, 2026

Built https://github.com/bitaxeorg/ESP-Miner/tree/early-access which includes this PR, upon setting up braiins via SV2 my 601 gamma fails over to secondary pool with this error
bitaxe-logs-2026-03-04T21-03-11-090Z.txt

Full braiins SV2 stratum url for reference:
stratum2+tcp://stratum.braiins.com:3333/9awtMD5KQgvRUh2yFbjVeT7b6hjipWcAsQHd6wEhgtDT9soosna

@warioishere
Copy link
Author

Built https://github.com/bitaxeorg/ESP-Miner/tree/early-access which includes this PR, upon setting up braiins via SV2 my 601 gamma fails over to secondary pool with this error bitaxe-logs-2026-03-04T21-03-11-090Z.txt

Full braiins SV2 stratum url for reference: stratum2+tcp://stratum.braiins.com:3333/9awtMD5KQgvRUh2yFbjVeT7b6hjipWcAsQHd6wEhgtDT9soosna

can you try standard channels, looks like braiins doesnt support extented channels. Also they dont completly follow SRI reference.

@sinnx3
Copy link

sinnx3 commented Mar 4, 2026

Built https://github.com/bitaxeorg/ESP-Miner/tree/early-access which includes this PR, upon setting up braiins via SV2 my 601 gamma fails over to secondary pool with this error bitaxe-logs-2026-03-04T21-03-11-090Z.txt
Full braiins SV2 stratum url for reference: stratum2+tcp://stratum.braiins.com:3333/9awtMD5KQgvRUh2yFbjVeT7b6hjipWcAsQHd6wEhgtDT9soosna

can you try standard channels, looks like braiins doesnt support extented channels. Also they dont completly follow SRI reference.

Working as intended with standard channels.
bitaxe-logs-2026-03-04T21-51-26-640Z.txt

@mutatrum
Copy link
Collaborator

mutatrum commented Mar 4, 2026

Built https://github.com/bitaxeorg/ESP-Miner/tree/early-access which includes this PR, upon setting up braiins via SV2 my 601 gamma fails over to secondary pool with this error bitaxe-logs-2026-03-04T21-03-11-090Z.txt
Full braiins SV2 stratum url for reference: stratum2+tcp://stratum.braiins.com:3333/9awtMD5KQgvRUh2yFbjVeT7b6hjipWcAsQHd6wEhgtDT9soosna

can you try standard channels, looks like braiins doesnt support extented channels. Also they dont completly follow SRI reference.

Are you sure? If Extended is not supported, why does it report Failed to parse OpenExtendedChannelSuccess, as seen in the logs?

@warioishere
Copy link
Author

warioishere commented Mar 4, 2026

Built https://github.com/bitaxeorg/ESP-Miner/tree/early-access which includes this PR, upon setting up braiins via SV2 my 601 gamma fails over to secondary pool with this error bitaxe-logs-2026-03-04T21-03-11-090Z.txt
Full braiins SV2 stratum url for reference: stratum2+tcp://stratum.braiins.com:3333/9awtMD5KQgvRUh2yFbjVeT7b6hjipWcAsQHd6wEhgtDT9soosna

can you try standard channels, looks like braiins doesnt support extented channels. Also they dont completly follow SRI reference.

Are you sure? If Extended is not supported, why does it report Failed to parse OpenExtendedChannelSuccess, as seen in the logs?

I'm not 100% sure on all the details, but what I can confirm is that BraiinsOS itself does not follow the SRI reference implementation fully. I tested with an S9 running BraiinsOS and couldn't get it to connect to the SRI reference server or my own TypeScript implementation. After hours of testing I found the following differences from the miner side:

  1. Different handshake protocol: BraiinsOS sends a proprietary STR2 cipher negotiation preamble before the Noise handshake, which standard SV2 implementations don't expect.
  2. Different DH algorithm: BraiinsOS uses X25519 (32-byte keys) instead of EllSwift/secp256k1 (64-byte keys) that the spec defines.
  3. Different certificate format: BraiinsOS uses Ed25519 signatures (76 bytes including metadata) rather than Schnorr signatures.
  4. Different Noise prologue: BraiinsOS uses a special prologue format, while standard SV2 uses an empty prologue.
  5. Standard channels only: BraiinsOS only opens standard mining channels (OpenStandardMiningChannel)

But interestingly their server themself seems to also accept SRI reference handshake. But maybe on Extented Channels they use different message types and formats?

The Problem is, their server is closed source, I have no insights about it, I wrote them a long mail 3 weeks ago asking for some details, but they of course didn't bother to answer me. Maybe @GitGab19 has some insights.

Edit:

I'll add some logging tomorrow to my dev firmware and see if I can find out what formats they send.

@GitGab19
Copy link

GitGab19 commented Mar 5, 2026

Braiins is using an older version of the OpenExtendedMiningChannel.Success message, which has been modified a couple of months ago in the specs.

That's the reason why the parsing is failing when using extended channels.

We're in touch with them, and they are gonna update their implementation soon, in the meantime you can still test this PR using standard channels if you want to connect to Braiins.

@plebhash
Copy link

plebhash commented Mar 5, 2026

this was the breaking change: stratum-mining/stratum#2044

@GitGab19
Copy link

GitGab19 commented Mar 5, 2026

I and @jayrmotta are testing this PR on a Bitaxe Supra (BM1368) against the SRI pool (75.119.150.111:3333) with both extended and standard channels.

Extended channels work fine, but when using standard channels, we noticed that almost every share is submitted multiple times, and so we get many duplicate-share errors.

Here a screenshot of the AxeOS logs:
bitaxe-logs

Here a screenshot of the corresponding SRI pool logs:
sri-pool

@warioishere
Copy link
Author

@GitGab19

as discussed, I have removed ntime_rolling, and in the current state, the nonce space is not fully used. For standard channels to work, you need Adams PR420 on top of this as stated here c21f890

you can also use the early access branch which has everything included:

https://github.com/bitaxeorg/ESP-Miner/tree/early-access

@mutatrum
Copy link
Collaborator

mutatrum commented Mar 13, 2026

@GitGab19

as discussed, I have removed ntime_rolling, and in the current state, the nonce space is not fully used. For standard channels to work, you need Adams PR420 on top of this as stated here c21f890

you can also use the early access branch which has everything included:

https://github.com/bitaxeorg/ESP-Miner/tree/early-access

I'm testing with the early-access release and both test servers from the opening post result in a 100% error rate and do not generate a proper hashrate. It's possible I messed up something with the merge?

@warioishere
Copy link
Author

warioishere commented Mar 13, 2026

@GitGab19
as discussed, I have removed ntime_rolling, and in the current state, the nonce space is not fully used. For standard channels to work, you need Adams PR420 on top of this as stated here c21f890
you can also use the early access branch which has everything included:
https://github.com/bitaxeorg/ESP-Miner/tree/early-access

I'm testing with the early-access release and both test servers from the opening post result in a 100% error rate and do not generate a proper hashrate. It's possible I messed up something with the merge?

For testing I merged PR420 into this PR and everything works as it should. Didnt try the early access tree

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.

8 participants