Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/stratifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#ifdef HAVE_SV2
#include "sv2_strat.h"
#include "sv2_jd.h"
#include "sv2_tx.h"
#endif

/* Consistent across all pool instances */
Expand Down Expand Up @@ -6988,7 +6989,6 @@ bool stratifier_sv2_merkle_root(int64_t instance_id, uint8_t merkle_root_le[32],
stratum_instance_t *client;
sdata_t *sdata = ckpool.sdata;
int cblen, i, en1len;
uint32_t *data32, *swap32;

if (!stratifier_sv2_snapshot_work(&snap, instance_id))
return false;
Expand Down Expand Up @@ -7016,9 +7016,11 @@ bool stratifier_sv2_merkle_root(int64_t instance_id, uint8_t merkle_root_le[32],
gen_hash(merkle_sha, merkle_root, 64);
memcpy(merkle_sha, merkle_root, 32);
}
data32 = (uint32_t *)merkle_sha;
swap32 = (uint32_t *)merkle_root_le;
flip_32(swap32, data32);
/* SV2 U256 fields carry the raw SHA256d digest bytes in little-endian
* integer order. gen_hash() already returns those bytes; applying
* CKPool's internal flip_32() here would word-swap the Merkle root and
* cause miners to hash a different header than the pool validates. */
sv2_merkle_root_to_u256_le(merkle_sha, merkle_root_le);

if (wb_id_out)
*wb_id_out = snap.wb_id;
Expand Down
5 changes: 5 additions & 0 deletions src/sv2_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ void sv2_merkle_root_from_path(const uint8_t coinbase_txid[32],
memcpy(root, pair, 32);
}

void sv2_merkle_root_to_u256_le(const uint8_t raw_hash[32], uint8_t out[32])
{
memcpy(out, raw_hash, 32);
}

double sv2_diff_from_nbits(uint32_t nbits)
{
uint32_t be = htobe32(nbits);
Expand Down
4 changes: 4 additions & 0 deletions src/sv2_tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ void sv2_merkle_root_from_path(const uint8_t coinbase_txid[32],
const uint8_t (*path)[32], int steps,
uint8_t root[32]);

/* A SHA256d digest is already the little-endian byte representation required
* by the SV2 U256 merkle_root field. */
void sv2_merkle_root_to_u256_le(const uint8_t raw_hash[32], uint8_t out[32]);

/*
* Network difficulty of an nbits value held as a host-order U32 — the form SV2
* carries it in, and the form that goes little-endian into a wire header.
Expand Down
16 changes: 16 additions & 0 deletions test/sv2_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,21 @@ static void test_merkle(void)
expect(!memcmp(root, want, 32), "path fold reproduces the tree root");
}

static void test_merkle_u256_wire_order(void)
{
static const uint8_t raw[32] = {
0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x20, 0x21, 0x22, 0x23, 0x30, 0x31, 0x32, 0x33,
0x40, 0x41, 0x42, 0x43, 0x50, 0x51, 0x52, 0x53,
0x60, 0x61, 0x62, 0x63, 0x70, 0x71, 0x72, 0x73,
};
uint8_t wire[32];

sv2_merkle_root_to_u256_le(raw, wire);
expect(!memcmp(raw, wire, 32),
"SV2 U256 merkle root preserves raw digest byte order");
}

/*
* nbits → difficulty. The byte order matters more than the arithmetic: the
* little-endian bytes of a wire header fed to libckpool's diff_from_nbits()
Expand Down Expand Up @@ -317,6 +332,7 @@ int main(void)
test_witness_tx();
test_walk_sequence();
test_merkle();
test_merkle_u256_wire_order();
test_nbits_diff();

if (failures) {
Expand Down