Skip to content

Commit 8bcfccb

Browse files
committed
Merge pull request #4076
397668e Deduplicate uint* comparison operator logic (Pieter Wuille) df9eb5e Move {Get,Set}Compact from bignum to uint256 (Pieter Wuille) a703150 Add multiplication and division to uint160/uint256 (Pieter Wuille) 4d480c8 Exception instead of assigning 0 in case of wrong vector length (Pieter Wuille) eb2cbd7 Deduplicate shared code between uint160 and uint256 (Pieter Wuille)
2 parents 82564e2 + 397668e commit 8bcfccb

File tree

13 files changed

+473
-508
lines changed

13 files changed

+473
-508
lines changed

src/bignum.h

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -269,71 +269,6 @@ class CBigNum : public BIGNUM
269269
return vch;
270270
}
271271

272-
// The "compact" format is a representation of a whole
273-
// number N using an unsigned 32bit number similar to a
274-
// floating point format.
275-
// The most significant 8 bits are the unsigned exponent of base 256.
276-
// This exponent can be thought of as "number of bytes of N".
277-
// The lower 23 bits are the mantissa.
278-
// Bit number 24 (0x800000) represents the sign of N.
279-
// N = (-1^sign) * mantissa * 256^(exponent-3)
280-
//
281-
// Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn().
282-
// MPI uses the most significant bit of the first byte as sign.
283-
// Thus 0x1234560000 is compact (0x05123456)
284-
// and 0xc0de000000 is compact (0x0600c0de)
285-
// (0x05c0de00) would be -0x40de000000
286-
//
287-
// Bitcoin only uses this "compact" format for encoding difficulty
288-
// targets, which are unsigned 256bit quantities. Thus, all the
289-
// complexities of the sign bit and using base 256 are probably an
290-
// implementation accident.
291-
//
292-
// This implementation directly uses shifts instead of going
293-
// through an intermediate MPI representation.
294-
CBigNum& SetCompact(unsigned int nCompact)
295-
{
296-
unsigned int nSize = nCompact >> 24;
297-
bool fNegative =(nCompact & 0x00800000) != 0;
298-
unsigned int nWord = nCompact & 0x007fffff;
299-
if (nSize <= 3)
300-
{
301-
nWord >>= 8*(3-nSize);
302-
BN_set_word(this, nWord);
303-
}
304-
else
305-
{
306-
BN_set_word(this, nWord);
307-
BN_lshift(this, this, 8*(nSize-3));
308-
}
309-
BN_set_negative(this, fNegative);
310-
return *this;
311-
}
312-
313-
unsigned int GetCompact() const
314-
{
315-
unsigned int nSize = BN_num_bytes(this);
316-
unsigned int nCompact = 0;
317-
if (nSize <= 3)
318-
nCompact = BN_get_word(this) << 8*(3-nSize);
319-
else
320-
{
321-
CBigNum bn;
322-
BN_rshift(&bn, this, 8*(nSize-3));
323-
nCompact = BN_get_word(&bn);
324-
}
325-
// The 0x00800000 bit denotes the sign.
326-
// Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
327-
if (nCompact & 0x00800000)
328-
{
329-
nCompact >>= 8;
330-
nSize++;
331-
}
332-
nCompact |= nSize << 24;
333-
nCompact |= (BN_is_negative(this) ? 0x00800000 : 0);
334-
return nCompact;
335-
}
336-
337272
void SetHex(const std::string& str)
338273
{
339274
// skip 0x

src/chainparams.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class CMainParams : public CChainParams {
110110
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
111111
nDefaultPort = 8333;
112112
nRPCPort = 8332;
113-
bnProofOfWorkLimit = CBigNum(~uint256(0) >> 32);
113+
bnProofOfWorkLimit = ~uint256(0) >> 32;
114114
nSubsidyHalvingInterval = 210000;
115115

116116
// Build the genesis block. Note that the output of the genesis coinbase cannot
@@ -233,7 +233,7 @@ class CRegTestParams : public CTestNetParams {
233233
pchMessageStart[2] = 0xb5;
234234
pchMessageStart[3] = 0xda;
235235
nSubsidyHalvingInterval = 150;
236-
bnProofOfWorkLimit = CBigNum(~uint256(0) >> 1);
236+
bnProofOfWorkLimit = ~uint256(0) >> 1;
237237
genesis.nTime = 1296688602;
238238
genesis.nBits = 0x207fffff;
239239
genesis.nNonce = 2;

src/chainparams.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class CChainParams
5656
const MessageStartChars& MessageStart() const { return pchMessageStart; }
5757
const vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
5858
int GetDefaultPort() const { return nDefaultPort; }
59-
const CBigNum& ProofOfWorkLimit() const { return bnProofOfWorkLimit; }
59+
const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; }
6060
int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; }
6161
virtual const CBlock& GenesisBlock() const = 0;
6262
virtual bool RequireRPCPassword() const { return true; }
@@ -75,7 +75,7 @@ class CChainParams
7575
vector<unsigned char> vAlertPubKey;
7676
int nDefaultPort;
7777
int nRPCPort;
78-
CBigNum bnProofOfWorkLimit;
78+
uint256 bnProofOfWorkLimit;
7979
int nSubsidyHalvingInterval;
8080
string strDataDir;
8181
vector<CDNSSeedData> vSeeds;

src/main.cpp

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,13 +1207,13 @@ static const int64_t nInterval = nTargetTimespan / nTargetSpacing;
12071207
//
12081208
unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
12091209
{
1210-
const CBigNum &bnLimit = Params().ProofOfWorkLimit();
1210+
const uint256 &bnLimit = Params().ProofOfWorkLimit();
12111211
// Testnet has min-difficulty blocks
12121212
// after nTargetSpacing*2 time between blocks:
12131213
if (TestNet() && nTime > nTargetSpacing*2)
12141214
return bnLimit.GetCompact();
12151215

1216-
CBigNum bnResult;
1216+
uint256 bnResult;
12171217
bnResult.SetCompact(nBase);
12181218
while (nTime > 0 && bnResult < bnLimit)
12191219
{
@@ -1272,8 +1272,10 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
12721272
nActualTimespan = nTargetTimespan*4;
12731273

12741274
// Retarget
1275-
CBigNum bnNew;
1275+
uint256 bnNew;
1276+
uint256 bnOld;
12761277
bnNew.SetCompact(pindexLast->nBits);
1278+
bnOld = bnNew;
12771279
bnNew *= nActualTimespan;
12781280
bnNew /= nTargetTimespan;
12791281

@@ -1283,23 +1285,25 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
12831285
/// debug print
12841286
LogPrintf("GetNextWorkRequired RETARGET\n");
12851287
LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
1286-
LogPrintf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString());
1287-
LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString());
1288+
LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString());
1289+
LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString());
12881290

12891291
return bnNew.GetCompact();
12901292
}
12911293

12921294
bool CheckProofOfWork(uint256 hash, unsigned int nBits)
12931295
{
1294-
CBigNum bnTarget;
1295-
bnTarget.SetCompact(nBits);
1296+
bool fNegative;
1297+
bool fOverflow;
1298+
uint256 bnTarget;
1299+
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
12961300

12971301
// Check range
1298-
if (bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit())
1302+
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
12991303
return error("CheckProofOfWork() : nBits below minimum work");
13001304

13011305
// Check proof of work matches claimed amount
1302-
if (hash > bnTarget.getuint256())
1306+
if (hash > bnTarget)
13031307
return error("CheckProofOfWork() : hash doesn't match nBits");
13041308

13051309
return true;
@@ -1338,7 +1342,7 @@ void CheckForkWarningConditions()
13381342
if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)
13391343
pindexBestForkTip = NULL;
13401344

1341-
if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6).getuint256()))
1345+
if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6)))
13421346
{
13431347
if (!fLargeWorkForkFound)
13441348
{
@@ -1394,7 +1398,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
13941398
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets
13951399
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
13961400
if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
1397-
pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7).getuint256() &&
1401+
pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7) &&
13981402
chainActive.Height() - pindexNewForkTip->nHeight < 72)
13991403
{
14001404
pindexBestForkTip = pindexNewForkTip;
@@ -1428,10 +1432,6 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
14281432
if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
14291433
{
14301434
pindexBestInvalid = pindexNew;
1431-
// The current code doesn't actually read the BestInvalidWork entry in
1432-
// the block database anymore, as it is derived from the flags in block
1433-
// index entry. We only write it for backward compatibility.
1434-
pblocktree->WriteBestInvalidWork(CBigNum(pindexBestInvalid->nChainWork));
14351435
uiInterface.NotifyBlocksChanged();
14361436
}
14371437
LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n",
@@ -2174,7 +2174,7 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
21742174
pindexNew->pprev = (*miPrev).second;
21752175
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
21762176
}
2177-
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256();
2177+
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork();
21782178
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
21792179

21802180
return pindexNew;
@@ -2351,11 +2351,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
23512351
return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"),
23522352
REJECT_CHECKPOINT, "time-too-old");
23532353
}
2354-
CBigNum bnNewBlock;
2355-
bnNewBlock.SetCompact(block.nBits);
2356-
CBigNum bnRequired;
2354+
bool fOverflow = false;
2355+
uint256 bnNewBlock;
2356+
bnNewBlock.SetCompact(block.nBits, NULL, &fOverflow);
2357+
uint256 bnRequired;
23572358
bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
2358-
if (bnNewBlock > bnRequired)
2359+
if (fOverflow || bnNewBlock > bnRequired)
23592360
{
23602361
return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"),
23612362
REJECT_INVALID, "bad-diffbits");
@@ -2926,7 +2927,7 @@ bool static LoadBlockIndexDB()
29262927
BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
29272928
{
29282929
CBlockIndex* pindex = item.second;
2929-
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork().getuint256();
2930+
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork();
29302931
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
29312932
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS))
29322933
setBlockIndexValid.insert(pindex);

src/main.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "bitcoin-config.h"
1111
#endif
1212

13-
#include "bignum.h"
1413
#include "chainparams.h"
1514
#include "coins.h"
1615
#include "core.h"
@@ -814,13 +813,19 @@ class CBlockIndex
814813
return (int64_t)nTime;
815814
}
816815

817-
CBigNum GetBlockWork() const
816+
uint256 GetBlockWork() const
818817
{
819-
CBigNum bnTarget;
820-
bnTarget.SetCompact(nBits);
821-
if (bnTarget <= 0)
818+
uint256 bnTarget;
819+
bool fNegative;
820+
bool fOverflow;
821+
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
822+
if (fNegative || fOverflow || bnTarget == 0)
822823
return 0;
823-
return (CBigNum(1)<<256) / (bnTarget+1);
824+
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
825+
// as it's too large for a uint256. However, as 2**256 is at least as large
826+
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
827+
// or ~bnTarget / (nTarget+1) + 1.
828+
return (~bnTarget / (bnTarget + 1)) + 1;
824829
}
825830

826831
bool CheckIndex() const

src/miner.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
466466
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
467467
{
468468
uint256 hash = pblock->GetHash();
469-
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
469+
uint256 hashTarget = uint256().SetCompact(pblock->nBits);
470470

471471
if (hash > hashTarget)
472472
return false;
@@ -552,7 +552,7 @@ void static BitcoinMiner(CWallet *pwallet)
552552
// Search
553553
//
554554
int64_t nStart = GetTime();
555-
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
555+
uint256 hashTarget = uint256().SetCompact(pblock->nBits);
556556
uint256 hashbuf[2];
557557
uint256& hash = *alignup<16>(hashbuf);
558558
while (true)
@@ -636,7 +636,7 @@ void static BitcoinMiner(CWallet *pwallet)
636636
{
637637
// Changing pblock->nTime can change work required on testnet:
638638
nBlockBits = ByteReverse(pblock->nBits);
639-
hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
639+
hashTarget.SetCompact(pblock->nBits);
640640
}
641641
}
642642
} }

src/rpcmining.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ Value getwork(const Array& params, bool fHelp)
363363
char phash1[64];
364364
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
365365

366-
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
366+
uint256 hashTarget = uint256().SetCompact(pblock->nBits);
367367

368368
Object result;
369369
result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
@@ -559,7 +559,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
559559
Object aux;
560560
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
561561

562-
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
562+
uint256 hashTarget = uint256().SetCompact(pblock->nBits);
563563

564564
static Array aMutable;
565565
if (aMutable.empty())

src/test/DoS_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2,
106106
return CheckNBits(nbits2, time2, nbits1, time1);
107107
int64_t deltaTime = time2-time1;
108108

109-
CBigNum required;
109+
uint256 required;
110110
required.SetCompact(ComputeMinWork(nbits1, deltaTime));
111-
CBigNum have;
111+
uint256 have;
112112
have.SetCompact(nbits2);
113113
return (have <= required);
114114
}

0 commit comments

Comments
 (0)