Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: joblo on August 23, 2019, 04:10:41 AM



Title: Q: Converting diff to hash
Post by: joblo on August 23, 2019, 04:10:41 AM
I'm an altcoin guy but this question applies to bitcoin.

The formula for converting share difficulty to an equivalent number of hashes
is documented on the bitcoin wiki: https://en.bitcoin.it/wiki/Difficulty

However, in my testing this formula produced incorrect results for altcoin algos.
I couldn't test sha256d as I don't have HW capable of supporting the extremely
high stratum diff. But since most altcoins were cloned from bitcoin I see no reason
why sha256d/bitcoin would be an exception.

Following are the comments I added to my code to explain my modification.
I arrived at the value through trial and error. Averaging over 100 shares the results
converged nicely to the miner's calculated hash rate for a cross section of algos.

Code:
// Bitcoin formula for converting a share's difficulty to an equivalent
// number of hashes.
//
//   https://en.bitcoin.it/wiki/Difficulty
//
//   H = D * 2**48 / 0xffff
//     = D * 2**32
//
// That formula doesn't seem to be accurate but an adjustment to the
// constant produces correct results.
//
// The formula used is:
//
//   hash = sharediff * 2**48 / 0x3fff
//        = sharediff * 2**30
//        = sharediff * diff2hash

const uint64_t diff2hash = 0x40000000ULL;

Although the numbers work I have no explanation for the discrepency with the documented
formula. I chose to decrease the denominator by a factor of 4 but increasing the numerator
would have the same effect so I don't know which one is "in error".

Is it simply a documentation error or am I missing something?


Title: Re: Q: Converting diff to hash
Post by: odolvlobo on August 24, 2019, 10:56:43 PM
Perhaps, sharediff is off by a factor of 4. Also, hashes are 256-bit values and using 64 bit values might be causing an overflow somewhere.


Title: Re: Q: Converting diff to hash
Post by: joblo on August 25, 2019, 01:12:11 AM
Thanks for refocussing my thinking. Your suggestion presumes a pre-existing bug
causing incorrect sharediff and my fix was the second wrong that made things right.

The more I think about it the more plausible it seems. I had assumed the sharediff was correct,
but it's never used except for user info so an error would have no side effects.

I've got some work to do.



Title: Re: Q: Converting diff to hash
Post by: joblo on August 25, 2019, 07:07:49 PM
TLDR: sharediff error was a bust, back to square 1.

I analyzed the code and did some testing to verify sharediff and the variables
used to calculate it.

The 256 bit arithmetic is done by converting the hash and target to double
using a simple polynomial:
Code:
 const double base = (const double)(1<<32) * (const double)(1<<32);  // 2**64
 double dhash = hash[0] + hash[1]*base + hash[2]*base**2 + hash[3]*base**3;

This will introduce some loss of precision but not a 4x error. The resulting precision
matches the precision of the networkstratum diff which is also double.

NetworkStratum diff is obtained from the pool and matches, therefore correct.

Hash is as accepted by the pool, therefore correct.

Target is calculated from the networkstratum diff. If the target was too low if would produce
occasional low diff rejected shares, which isn't happening.

If the target was too high there would be no errors but the miner would neglect to
submit shares that would be accepted, resulting in a lower hashrate at the pool.
That was not observed.

In addition, I did some testing by raising the difficulty by 4x and low difficulty shares
were produced. 2x higher also produced low diff shares proving the original target
was neither too low nor too high.

The formula used:

sharediff = networkstratumdiff * target / hash

I can find nothing wrong with the sharediff calculation. It points back to the constant divisor
in the wiki arcticle being in error.

I'm willing ro accept it's simply a documentation error. My confidence in my code has increased
by doing a detailed analysis, however, it's still a hack without a proper explanation.

Edit: corrected references to stratum diff instead of network diff