Post
Topic
Board Announcements (Altcoins)
Re: DNotes 2.0 - Bridging the Gap Between the Centralized and Decentralized World
by
flound1129
on 28/02/2018, 19:32:04 UTC
Found the issue -- it's a floating point bug in GetBlockValue()


Thanks flound1129! That is correct, some blocks like 2103797 reward 20.36265624 rather than (25*math.pow(0.95,4)) 20.36265625. The mystery remains, why your node rejects it and all the others seem fine with it.

It's not really a mystery, pow(0.95,4)*25 at https://github.com/DNotesCoin/DNotes/blob/master/src/main.cpp#L851-L853 evaluates to 20.362656249999997 on my system, which evaluates to False in the comparison at https://github.com/DNotesCoin/DNotes/blob/master/src/main.cpp#L1431 when the coinbase transaction vtx[0].getValueOut() == 20.36265625 and thus the block is considered invalid.

Minor correction, since nSubsidy starts out as an int64, the math should be pow(0.95,4)*2500000000 == 2036265624.9999998, which is being cast back to an int64 type at https://github.com/DNotesCoin/DNotes/blob/master/src/main.cpp#L853

Expected behavior when casting a floating point value to an int is that the number is truncated (not rounded).  See https://stackoverflow.com/questions/9695329/c-how-to-round-a-double-to-an-int

Patching main.cpp in the following manner (assuming rounding is the desired behavior) appears to fix the issue:

Code:
diff --git a/src/main.cpp b/src/main.cpp
index 4773964..48d7b3c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -850,7 +850,7 @@ int64 static GetBlockValue(int nHeight, int64 nFees)
        {
                int yearsElapsed = nHeight / 525949;
                double nReductionPercentage = pow(0.95,yearsElapsed);
-               nSubsidy = nSubsidy * nReductionPercentage;
+               nSubsidy = (int64) ((nSubsidy * nReductionPercentage)+0.5);
        }
     return nSubsidy + nFees;
 }