Skip to content

Commit e542728

Browse files
author
MarcoFalke
committed
Merge #11303: Fix estimatesmartfee rounding display issue
1789e46 Force explicit double -> int conversion for CFeeRate constructor (Matt Corallo) 53a6590 Make float <-> int casts explicit outside of test, qt, CFeeRate (Matt Corallo) 0b1b914 Remove countMaskInv caching in bench framework (Matt Corallo) Pull request description: This fixes an issue where estimatesmartfee which matches at the min relay fee will return 999 sat/byte instead of 1000 sat/byte due to a float rounding issue. I went ahead and made all float <-> int conversion outside of test/qt explicit (test only had one or two more, Qt had quite a few, including many in the Qt headers themselves) and added overloads to CFeeRate to force callers to do an explicit round themselves. Easy to test with -Wfloat-conversion. Tree-SHA512: 66087b08e5dfca67506da54ae057c2f9d86184415e8fa4fa0199e38839e06a3ce96c836fcb7593b7d960065f5240c594ff3a0cfa14333ac528421f5aeac835c9
2 parents 7632310 + 1789e46 commit e542728

File tree

9 files changed

+23
-21
lines changed

9 files changed

+23
-21
lines changed

src/bench/bench.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,20 @@ bool benchmark::State::KeepRunning()
5555
else {
5656
now = gettimedouble();
5757
double elapsed = now - lastTime;
58-
double elapsedOne = elapsed * countMaskInv;
58+
double elapsedOne = elapsed / (countMask + 1);
5959
if (elapsedOne < minTime) minTime = elapsedOne;
6060
if (elapsedOne > maxTime) maxTime = elapsedOne;
6161

6262
// We only use relative values, so don't have to handle 64-bit wrap-around specially
6363
nowCycles = perf_cpucycles();
64-
uint64_t elapsedOneCycles = (nowCycles - lastCycles) * countMaskInv;
64+
uint64_t elapsedOneCycles = (nowCycles - lastCycles) / (countMask + 1);
6565
if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
6666
if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
6767

6868
if (elapsed*128 < maxElapsed) {
6969
// If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
7070
// The restart avoids including the overhead of this code in the measurement.
7171
countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
72-
countMaskInv = 1./(countMask+1);
7372
count = 0;
7473
minTime = std::numeric_limits<double>::max();
7574
maxTime = std::numeric_limits<double>::min();
@@ -81,7 +80,6 @@ bool benchmark::State::KeepRunning()
8180
uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
8281
if ((count & newCountMask)==0) {
8382
countMask = newCountMask;
84-
countMaskInv = 1./(countMask+1);
8583
}
8684
}
8785
}

src/bench/bench.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace benchmark {
4141
std::string name;
4242
double maxElapsed;
4343
double beginTime;
44-
double lastTime, minTime, maxTime, countMaskInv;
44+
double lastTime, minTime, maxTime;
4545
uint64_t count;
4646
uint64_t countMask;
4747
uint64_t beginCycles;
@@ -55,7 +55,6 @@ namespace benchmark {
5555
minCycles = std::numeric_limits<uint64_t>::max();
5656
maxCycles = std::numeric_limits<uint64_t>::min();
5757
countMask = 1;
58-
countMaskInv = 1./(countMask + 1);
5958
}
6059
bool KeepRunning();
6160
};

src/policy/feerate.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ class CFeeRate
2020
{
2121
private:
2222
CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
23+
2324
public:
2425
/** Fee rate of 0 satoshis per kB */
2526
CFeeRate() : nSatoshisPerK(0) { }
26-
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
27+
template<typename I>
28+
CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
29+
// We've previously had bugs creep in from silent double->int conversion...
30+
static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
31+
}
2732
/** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
2833
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
2934
/**

src/policy/fees.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
714714
if (median < 0)
715715
return CFeeRate(0);
716716

717-
return CFeeRate(median);
717+
return CFeeRate(llround(median));
718718
}
719719

720720
unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
@@ -901,7 +901,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
901901

902902
if (median < 0) return CFeeRate(0); // error condition
903903

904-
return CFeeRate(median);
904+
return CFeeRate(llround(median));
905905
}
906906

907907

@@ -1043,5 +1043,5 @@ CAmount FeeFilterRounder::round(CAmount currentMinFee)
10431043
if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
10441044
it--;
10451045
}
1046-
return *it;
1046+
return static_cast<CAmount>(*it);
10471047
}

src/rpc/net.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
146146
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
147147
if (stats.dPingTime > 0.0)
148148
obj.push_back(Pair("pingtime", stats.dPingTime));
149-
if (stats.dMinPing < std::numeric_limits<int64_t>::max()/1e6)
149+
if (stats.dMinPing < static_cast<double>(std::numeric_limits<int64_t>::max())/1e6)
150150
obj.push_back(Pair("minping", stats.dMinPing));
151151
if (stats.dPingWait > 0.0)
152152
obj.push_back(Pair("pingwait", stats.dPingWait));

src/test/mempool_tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -559,15 +559,15 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
559559
// ... we should keep the same min fee until we get a block
560560
pool.removeForBlock(vtx, 1);
561561
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
562-
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
562+
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0));
563563
// ... then feerate should drop 1/2 each halflife
564564

565565
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
566-
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4);
566+
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0));
567567
// ... with a 1/2 halflife when mempool is < 1/2 its target size
568568

569569
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
570-
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8);
570+
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0));
571571
// ... with a 1/4 halflife when mempool is < 1/4 its target size
572572

573573
SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);

src/txmempool.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) cons
981981
CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
982982
LOCK(cs);
983983
if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
984-
return CFeeRate(rollingMinimumFeeRate);
984+
return CFeeRate(llround(rollingMinimumFeeRate));
985985

986986
int64_t time = GetTime();
987987
if (time > lastRollingFeeUpdate + 10) {
@@ -999,7 +999,7 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
999999
return CFeeRate(0);
10001000
}
10011001
}
1002-
return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee);
1002+
return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
10031003
}
10041004

10051005
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {

src/txmempool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ class CTxMemPool
507507
* check does nothing.
508508
*/
509509
void check(const CCoinsViewCache *pcoins) const;
510-
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; }
510+
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); }
511511

512512
// addUnchecked must updated state for all ancestors of a given transaction,
513513
// to track size/count of descendant transactions. First version of

src/wallet/wallet.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,11 +409,11 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
409409
{
410410
int64_t nStartTime = GetTimeMillis();
411411
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
412-
pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
412+
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))));
413413

414414
nStartTime = GetTimeMillis();
415415
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
416-
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
416+
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
417417

418418
if (pMasterKey.second.nDeriveIterations < 25000)
419419
pMasterKey.second.nDeriveIterations = 25000;
@@ -615,11 +615,11 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
615615
CCrypter crypter;
616616
int64_t nStartTime = GetTimeMillis();
617617
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
618-
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
618+
kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(GetTimeMillis() - nStartTime)));
619619

620620
nStartTime = GetTimeMillis();
621621
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
622-
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
622+
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
623623

624624
if (kMasterKey.nDeriveIterations < 25000)
625625
kMasterKey.nDeriveIterations = 25000;

0 commit comments

Comments
 (0)