Skip to content

Commit 28ee6a7

Browse files
committed
Fix uint256 comparison for stake modifier candidate selection
Upgrading to Bitcoin's latest uint256 type changes the backing storage from an array of 32-bit integers to a byte array. Since the comparison operator implementations changed as well, the less-than comparison for sorting the vector of candidates can produce different block orderings for the historical stake modifier than the original order from before. To ensure that we reproduce the same stake modifier values out of this candidate set, we adopt Peercoin's strategy for sorting the collection that behaves like the old uint256 implementation. peercoin/peercoin@4f8df68
1 parent 4937e88 commit 28ee6a7

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

src/kernel.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,36 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod
206206
pindex = pindex->pprev;
207207
}
208208
int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0;
209-
std::sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end());
209+
210+
// Shuffle before sort
211+
for(int i = vSortedByTimestamp.size() - 1; i > 1; --i)
212+
std::swap(vSortedByTimestamp[i], vSortedByTimestamp[GetRand(i)]);
213+
214+
// Upgrading to Bitcoin's latest uint256 type changes the backing storage
215+
// from an array of 32-bit integers to a byte array. Since the comparison
216+
// operator implementations changed as well, the less-than comparison for
217+
// sorting the vector of candidates can produce different block orderings
218+
// for the historical stake modifier than the original order from before.
219+
//
220+
// To ensure that we reproduce the same stake modifier values out of this
221+
// candidate set, we adopt Peercoin's strategy for sorting the collection
222+
// that behaves like the old uint256 implementation:
223+
//
224+
sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end(), [] (const pair<int64_t, uint256> &a, const pair<int64_t, uint256> &b)
225+
{
226+
if (a.first != b.first)
227+
return a.first < b.first;
228+
// Timestamp equals - compare block hashes
229+
const uint32_t *pa = a.second.GetDataPtr();
230+
const uint32_t *pb = b.second.GetDataPtr();
231+
int cnt = 256 / 32;
232+
do {
233+
--cnt;
234+
if (pa[cnt] != pb[cnt])
235+
return pa[cnt] < pb[cnt];
236+
} while(cnt);
237+
return false; // Elements are equal
238+
});
210239

211240
// Select 64 blocks from candidate blocks to generate stake modifier
212241
uint64_t nStakeModifierNew = 0;

src/uint256.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class base_blob
5151
void SetHex(const std::string& str);
5252
std::string ToString() const;
5353

54+
const uint32_t *GetDataPtr() const
55+
{
56+
return (const uint32_t *)data;
57+
}
58+
5459
unsigned char* begin()
5560
{
5661
return &data[0];

0 commit comments

Comments
 (0)