Skip to content

adjust hex conversion on sv1 to use bitcoin::hashes::hex#2205

Merged
GitGab19 merged 3 commits into
stratum-mining:mainfrom
lucasbalieiro:update-hex-conversion-sv1
Jun 18, 2026
Merged

adjust hex conversion on sv1 to use bitcoin::hashes::hex#2205
GitGab19 merged 3 commits into
stratum-mining:mainfrom
lucasbalieiro:update-hex-conversion-sv1

Conversation

@lucasbalieiro

@lucasbalieiro lucasbalieiro commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

closes #2201.

This PR replaces the use of bitcoin_hashes@0.3.2, which can panic when processing certain multibyte characters, with bitcoin::hashes::hex.

It also centralizes hex decoding behind a single utility function, crate::utils::hex_decode. Prior to this change, there were multiple hex conversion implementations scattered throughout the codebase, making behavior harder to reason about and maintain consistently.

While working on this issue, I also noticed inconsistent handling of odd-length hex strings. Some call sites would pad the input before decoding, while others would not.

After investigating the historical context (see #896), I introduced a dedicated wrapper named hex_decode_with_padding. The goal is to make padding an explicit and deliberate choice rather than an implicit side effect hidden within the decoding logic.

At the moment, hex_decode_with_padding is only used in the TryFrom implementation for Extranonce, which is the use case discussed in #896. The padding behavior for Extranonce also appears to be required to satisfy the unit test introduced in #1791.

@lucasbalieiro lucasbalieiro force-pushed the update-hex-conversion-sv1 branch from fbfd92f to a75874c Compare June 17, 2026 18:44
@lucasbalieiro lucasbalieiro marked this pull request as ready for review June 17, 2026 19:02
Comment on lines +733 to +741
let json = r#"{
"id": 34560326215225189,
"error": null,
"result": [
[["", [-32088499539804252, {"": null}]], null, false],
"55555ʛ",
-1.0900715865557387e-175
]
}"#;

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.

non-blocking clanker review:

This regression test includes multiple invalid fields (subscriptions shape and extra_nonce2_size as a negative float), so it may pass without exercising the non-ASCII extranonce decode path.

Suggestion: keep non-target fields valid (e.g. valid subscriptions + extra_nonce2_size: 4) so the test isolates the non-ASCII hex behavior.

@lucasbalieiro lucasbalieiro Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

addresed, force-pushed d501a1a

Comment thread sv1/src/utils.rs
Comment on lines +61 to +78
pub fn hex_decode_with_padding(s: &str) -> Result<Vec<u8>, Error<'static>> {
let padded;

let s = if s.len() % 2 != 0 {
padded = format!("0{s}");
&padded
} else {
Vec::<u8>::from_hex(s).map_err(Error::HexError)
}
s
};

hex_decode(s)
}

impl<'a> TryFrom<&str> for Extranonce<'a> {
type Error = error::Error<'a>;

fn try_from(value: &str) -> Result<Self, Error<'a>> {
Ok(Extranonce(B032::try_from(hex_decode(value)?)?))
Ok(Extranonce(B032::try_from(hex_decode_with_padding(value)?)?))

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.

does any such scenario even happen, odd length hex string? discussion is too long, some tldr would be helpful.

And considering decode_with_padding is used on once, maybe inlining would be ok.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

TL;DR: At the time of the original issue, a faulty firmware was sending an odd-length hex extranonce, which caused errors in tproxy.

I agree that this scenario should not occur, and ideally we should reject invalid extranonce values instead of trying to "fix" them via left-padding (IMO).

however, following the history of the codebase, this behavior was intentionally carried over into the New TProxy work:
f0a69aa

If I remove the left-padding behavior now, it will break an existing unit test (which tells me that this is intentional). Since changing the semantics of Extranonce parsing is not the goal of this PR, I opted to preserve the current behavior. I also don't know whether any downstream users are relying on this behavior today, so keeping it seemed like the safer option for a targeted fix.

Regarding inlining hex_decode_with_padding, I wouldn't oppose that. My main concern is that, if we decide to keep left-padding in specific scenarios, we should avoid ending up in the same situation we had before, where hex decoding logic was scattered across the codebase with slightly different implementations.

One of the goals of this PR was to centralize hex decoding behind a small set of helpers so that any future changes to validation or decoding behavior can be made in a single place.

@lucasbalieiro lucasbalieiro force-pushed the update-hex-conversion-sv1 branch from 6b9160b to 974696c Compare June 18, 2026 02:50
@lucasbalieiro lucasbalieiro force-pushed the update-hex-conversion-sv1 branch from 974696c to d501a1a Compare June 18, 2026 03:29
@GitGab19 GitGab19 merged commit f768792 into stratum-mining:main Jun 18, 2026
14 checks passed
@lucasbalieiro lucasbalieiro deleted the update-hex-conversion-sv1 branch June 18, 2026 15:08
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.

consider moving away from bitcoin_hashes

4 participants