Fix underflow rounding issue:

Very small payment could fail when STAmount::mulRound underflowed
and returned zero, when it should have rounded up to the smallest
representable value.
This commit is contained in:
seelabs
2015-11-04 16:18:43 -05:00
committed by Nik Bougalis
parent 4626992474
commit 999701e384
15 changed files with 200 additions and 50 deletions

View File

@@ -1140,7 +1140,8 @@ canonicalizeRound (bool native, std::uint64_t& value, int& offset, bool roundUp)
STAmount
mulRound (STAmount const& v1, STAmount const& v2,
Issue const& issue, bool roundUp)
Issue const& issue, bool roundUp,
STAmountCalcSwitchovers const& switchovers)
{
if (v1 == zero || v2 == zero)
return {issue};
@@ -1203,12 +1204,21 @@ mulRound (STAmount const& v1, STAmount const& v2,
int offset = offset1 + offset2 + 14;
canonicalizeRound (
isXRP (issue), amount, offset, resultNegative != roundUp);
return STAmount (issue, amount, offset, resultNegative);
STAmount result (issue, amount, offset, resultNegative);
if (switchovers.enableUnderflowFix () && roundUp && !resultNegative && !result)
{
// return the smallest value above zero
amount = STAmount::cMinValue;
offset = STAmount::cMinOffset;
return STAmount (issue, amount, offset, resultNegative);
}
return result;
}
STAmount
divRound (STAmount const& num, STAmount const& den,
Issue const& issue, bool roundUp)
Issue const& issue, bool roundUp,
STAmountCalcSwitchovers const& switchovers)
{
if (den == zero)
Throw<std::runtime_error> ("division by zero");
@@ -1254,7 +1264,15 @@ divRound (STAmount const& num, STAmount const& den,
int offset = numOffset - denOffset - 17;
canonicalizeRound (
isXRP (issue), amount, offset, resultNegative != roundUp);
return STAmount (issue, amount, offset, resultNegative);
STAmount result (issue, amount, offset, resultNegative);
if (switchovers.enableUnderflowFix () && roundUp && !resultNegative && !result)
{
// return the smallest value above zero
amount = STAmount::cMinValue;
offset = STAmount::cMinOffset;
return STAmount (issue, amount, offset, resultNegative);
}
return result;
}
// compute (value)*(mul)/(div) - avoid overflow but keep precision
@@ -1291,4 +1309,22 @@ mulDivNoThrow(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
}
}
std::uint32_t
STAmountCalcSwitchovers::enableUnderflowFixCloseTime ()
{
// Mon Dec 28 10:00:00am PST
return 504'640'800;
}
STAmountCalcSwitchovers::STAmountCalcSwitchovers (std::uint32_t parentCloseTime)
{
enableUnderflowFix_ = parentCloseTime > enableUnderflowFixCloseTime();
}
bool STAmountCalcSwitchovers::enableUnderflowFix () const
{
return enableUnderflowFix_;
}
} // ripple