mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Add IOU and XRP Amounts
This commit is contained in:
@@ -2552,6 +2552,8 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\protocol\AccountID.h">
|
<ClInclude Include="..\..\src\ripple\protocol\AccountID.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\protocol\AmountSpec.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\protocol\Book.h">
|
<ClInclude Include="..\..\src\ripple\protocol\Book.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\protocol\BuildInfo.h">
|
<ClInclude Include="..\..\src\ripple\protocol\BuildInfo.h">
|
||||||
|
|||||||
@@ -3099,6 +3099,9 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\protocol\AccountID.h">
|
<ClInclude Include="..\..\src\ripple\protocol\AccountID.h">
|
||||||
<Filter>ripple\protocol</Filter>
|
<Filter>ripple\protocol</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\protocol\AmountSpec.h">
|
||||||
|
<Filter>ripple\protocol</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\protocol\Book.h">
|
<ClInclude Include="..\..\src\ripple\protocol\Book.h">
|
||||||
<Filter>ripple\protocol</Filter>
|
<Filter>ripple\protocol</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/ledger/ReadView.h>
|
#include <ripple/ledger/ReadView.h>
|
||||||
|
#include <ripple/protocol/AmountSpec.h>
|
||||||
#include <ripple/protocol/STAmount.h>
|
#include <ripple/protocol/STAmount.h>
|
||||||
#include <ripple/protocol/Indexes.h>
|
#include <ripple/protocol/Indexes.h>
|
||||||
|
|
||||||
@@ -48,6 +49,16 @@ creditLimit (
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOUAmount
|
||||||
|
creditLimit2 (
|
||||||
|
ReadView const& v,
|
||||||
|
AccountID const& acc,
|
||||||
|
AccountID const& iss,
|
||||||
|
Currency const& cur)
|
||||||
|
{
|
||||||
|
return toAmount<IOUAmount> (creditLimit (v, acc, iss, cur));
|
||||||
|
}
|
||||||
|
|
||||||
STAmount creditBalance (
|
STAmount creditBalance (
|
||||||
ReadView const& view,
|
ReadView const& view,
|
||||||
AccountID const& account,
|
AccountID const& account,
|
||||||
@@ -72,4 +83,15 @@ STAmount creditBalance (
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOUAmount
|
||||||
|
creditBalance2 (
|
||||||
|
ReadView const& v,
|
||||||
|
AccountID const& acc,
|
||||||
|
AccountID const& iss,
|
||||||
|
Currency const& cur)
|
||||||
|
{
|
||||||
|
return toAmount<IOUAmount> (creditBalance (v, acc, iss, cur));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <ripple/ledger/View.h>
|
#include <ripple/ledger/View.h>
|
||||||
#include <ripple/protocol/STAmount.h>
|
#include <ripple/protocol/STAmount.h>
|
||||||
|
#include <ripple/protocol/IOUAmount.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -38,6 +39,13 @@ STAmount creditLimit (
|
|||||||
AccountID const& issuer,
|
AccountID const& issuer,
|
||||||
Currency const& currency);
|
Currency const& currency);
|
||||||
|
|
||||||
|
IOUAmount
|
||||||
|
creditLimit2 (
|
||||||
|
ReadView const& v,
|
||||||
|
AccountID const& acc,
|
||||||
|
AccountID const& iss,
|
||||||
|
Currency const& cur);
|
||||||
|
|
||||||
/** Returns the amount of IOUs issued by issuer that are held by an account
|
/** Returns the amount of IOUs issued by issuer that are held by an account
|
||||||
@param ledger the ledger to check against.
|
@param ledger the ledger to check against.
|
||||||
@param account the account of interest.
|
@param account the account of interest.
|
||||||
@@ -50,6 +58,13 @@ STAmount creditBalance (
|
|||||||
AccountID const& issuer,
|
AccountID const& issuer,
|
||||||
Currency const& currency);
|
Currency const& currency);
|
||||||
|
|
||||||
|
IOUAmount
|
||||||
|
creditBalance2 (
|
||||||
|
ReadView const& v,
|
||||||
|
AccountID const& acc,
|
||||||
|
AccountID const& iss,
|
||||||
|
Currency const& cur);
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED
|
||||||
|
#define RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/basics/Log.h>
|
#include <ripple/basics/Log.h>
|
||||||
#include <ripple/protocol/TxFlags.h>
|
#include <ripple/protocol/TxFlags.h>
|
||||||
#include <ripple/test/jtx.h>
|
#include <ripple/test/jtx.h>
|
||||||
@@ -134,3 +137,5 @@ private:
|
|||||||
|
|
||||||
} // test
|
} // test
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
289
src/ripple/protocol/AmountSpec.h
Normal file
289
src/ripple/protocol/AmountSpec.h
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_PROTOCOL_AMOUNTSPEC_H_INCLUDED
|
||||||
|
#define RIPPLE_PROTOCOL_AMOUNTSPEC_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/protocol/IOUAmount.h>
|
||||||
|
#include <ripple/protocol/XRPAmount.h>
|
||||||
|
#include <ripple/protocol/STAmount.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
struct AmountSpec
|
||||||
|
{
|
||||||
|
bool native;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
XRPAmount xrp;
|
||||||
|
IOUAmount iou;
|
||||||
|
};
|
||||||
|
boost::optional<AccountID> issuer;
|
||||||
|
boost::optional<Currency> currency;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend
|
||||||
|
std::ostream&
|
||||||
|
operator << (
|
||||||
|
std::ostream& stream,
|
||||||
|
AmountSpec const& amt)
|
||||||
|
{
|
||||||
|
if (amt.native)
|
||||||
|
stream << to_string (amt.xrp);
|
||||||
|
else
|
||||||
|
stream << to_string (amt.iou);
|
||||||
|
if (amt.currency)
|
||||||
|
stream << "/(" << *amt.currency << ")";
|
||||||
|
if (amt.issuer)
|
||||||
|
stream << "/" << *amt.issuer << "";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EitherAmount
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool native = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
IOUAmount iou;
|
||||||
|
XRPAmount xrp;
|
||||||
|
};
|
||||||
|
|
||||||
|
EitherAmount () = default;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
EitherAmount (IOUAmount const& a)
|
||||||
|
:iou(a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
// ignore warning about half of iou amount being uninitialized
|
||||||
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
#endif
|
||||||
|
explicit
|
||||||
|
EitherAmount (XRPAmount const& a)
|
||||||
|
:xrp(a)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
native = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
explicit
|
||||||
|
EitherAmount (AmountSpec const& a)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
native = a.native;
|
||||||
|
#endif
|
||||||
|
if (a.native)
|
||||||
|
xrp = a.xrp;
|
||||||
|
else
|
||||||
|
iou = a.iou;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T&
|
||||||
|
get (EitherAmount& amt)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(T) == -1, "Must used specialized function");
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
IOUAmount&
|
||||||
|
get<IOUAmount> (EitherAmount& amt)
|
||||||
|
{
|
||||||
|
assert (!amt.native);
|
||||||
|
return amt.iou;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
XRPAmount&
|
||||||
|
get<XRPAmount> (EitherAmount& amt)
|
||||||
|
{
|
||||||
|
assert (amt.native);
|
||||||
|
return amt.xrp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T const&
|
||||||
|
get (EitherAmount const& amt)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(T) == -1, "Must used specialized function");
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
IOUAmount const&
|
||||||
|
get<IOUAmount> (EitherAmount const& amt)
|
||||||
|
{
|
||||||
|
assert (!amt.native);
|
||||||
|
return amt.iou;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
XRPAmount const&
|
||||||
|
get<XRPAmount> (EitherAmount const& amt)
|
||||||
|
{
|
||||||
|
assert (amt.native);
|
||||||
|
return amt.xrp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
AmountSpec
|
||||||
|
toAmountSpec (STAmount const& amt)
|
||||||
|
{
|
||||||
|
assert (amt.mantissa () < std::numeric_limits<std::int64_t>::max ());
|
||||||
|
bool const isNeg = amt.negative ();
|
||||||
|
std::int64_t const sMant =
|
||||||
|
isNeg ? - std::int64_t (amt.mantissa ()) : amt.mantissa ();
|
||||||
|
AmountSpec result;
|
||||||
|
|
||||||
|
result.native = isXRP (amt);
|
||||||
|
if (result.native)
|
||||||
|
{
|
||||||
|
result.xrp = XRPAmount (sMant);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.iou = IOUAmount (sMant, amt.exponent ());
|
||||||
|
result.issuer = amt.issue().account;
|
||||||
|
result.currency = amt.issue().currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
AmountSpec
|
||||||
|
toAmountSpec (
|
||||||
|
EitherAmount const& ea,
|
||||||
|
boost::optional<Currency> const& c)
|
||||||
|
{
|
||||||
|
AmountSpec r;
|
||||||
|
r.native = (!c || isXRP (*c));
|
||||||
|
r.currency = c;
|
||||||
|
assert (ea.native == r.native);
|
||||||
|
if (r.native)
|
||||||
|
{
|
||||||
|
r.xrp = ea.xrp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.iou = ea.iou;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
STAmount
|
||||||
|
toSTAmount (IOUAmount const& iou, Issue const& iss)
|
||||||
|
{
|
||||||
|
bool const isNeg = iou.signum() < 0;
|
||||||
|
std::uint64_t const umant = isNeg ? - iou.mantissa () : iou.mantissa ();
|
||||||
|
return STAmount (iss, umant, iou.exponent (), /*native*/ false, isNeg,
|
||||||
|
STAmount::unchecked ());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
STAmount
|
||||||
|
toSTAmount (IOUAmount const& iou)
|
||||||
|
{
|
||||||
|
return toSTAmount (iou, noIssue ());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
STAmount
|
||||||
|
toSTAmount (XRPAmount const& xrp)
|
||||||
|
{
|
||||||
|
bool const isNeg = xrp.signum() < 0;
|
||||||
|
std::uint64_t const umant = isNeg ? - xrp.drops () : xrp.drops ();
|
||||||
|
return STAmount (umant, isNeg);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
STAmount
|
||||||
|
toSTAmount (XRPAmount const& xrp, Issue const& iss)
|
||||||
|
{
|
||||||
|
assert (isXRP(iss.account) && isXRP(iss.currency));
|
||||||
|
return toSTAmount (xrp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T
|
||||||
|
toAmount (STAmount const& amt)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(T) == -1, "Must used specialized function");
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
STAmount
|
||||||
|
toAmount<STAmount> (STAmount const& amt)
|
||||||
|
{
|
||||||
|
return amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
IOUAmount
|
||||||
|
toAmount<IOUAmount> (STAmount const& amt)
|
||||||
|
{
|
||||||
|
assert (amt.mantissa () < std::numeric_limits<std::int64_t>::max ());
|
||||||
|
bool const isNeg = amt.negative ();
|
||||||
|
std::int64_t const sMant =
|
||||||
|
isNeg ? - std::int64_t (amt.mantissa ()) : amt.mantissa ();
|
||||||
|
|
||||||
|
assert (! isXRP (amt));
|
||||||
|
return IOUAmount (sMant, amt.exponent ());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline
|
||||||
|
XRPAmount
|
||||||
|
toAmount<XRPAmount> (STAmount const& amt)
|
||||||
|
{
|
||||||
|
assert (amt.mantissa () < std::numeric_limits<std::int64_t>::max ());
|
||||||
|
bool const isNeg = amt.negative ();
|
||||||
|
std::int64_t const sMant =
|
||||||
|
isNeg ? - std::int64_t (amt.mantissa ()) : amt.mantissa ();
|
||||||
|
AmountSpec result;
|
||||||
|
|
||||||
|
assert (isXRP (amt));
|
||||||
|
return XRPAmount (sMant);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -140,6 +140,13 @@ public:
|
|||||||
std::string
|
std::string
|
||||||
to_string (IOUAmount const& amount);
|
to_string (IOUAmount const& amount);
|
||||||
|
|
||||||
|
IOUAmount
|
||||||
|
mulRatio (
|
||||||
|
IOUAmount const& amt,
|
||||||
|
std::uint32_t num,
|
||||||
|
std::uint32_t den,
|
||||||
|
bool roundUp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,7 +20,11 @@
|
|||||||
#ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
|
#ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
|
||||||
#define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
|
#define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/protocol/AmountSpec.h>
|
||||||
|
#include <ripple/protocol/IOUAmount.h>
|
||||||
#include <ripple/protocol/STAmount.h>
|
#include <ripple/protocol/STAmount.h>
|
||||||
|
#include <ripple/protocol/XRPAmount.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
@@ -35,11 +39,18 @@ namespace ripple {
|
|||||||
For offers, "in" is always TakerPays and "out" is
|
For offers, "in" is always TakerPays and "out" is
|
||||||
always TakerGets.
|
always TakerGets.
|
||||||
*/
|
*/
|
||||||
struct Amounts
|
template<class TIn, class TOut>
|
||||||
|
struct TAmounts
|
||||||
{
|
{
|
||||||
Amounts() = default;
|
TAmounts() = default;
|
||||||
|
|
||||||
Amounts (STAmount const& in_, STAmount const& out_)
|
TAmounts (beast::Zero, beast::Zero)
|
||||||
|
: in (beast::zero)
|
||||||
|
, out (beast::zero)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TAmounts (TIn const& in_, TOut const& out_)
|
||||||
: in (in_)
|
: in (in_)
|
||||||
, out (out_)
|
, out (out_)
|
||||||
{
|
{
|
||||||
@@ -52,20 +63,46 @@ struct Amounts
|
|||||||
return in <= zero || out <= zero;
|
return in <= zero || out <= zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
STAmount in;
|
TAmounts& operator+=(TAmounts const& rhs)
|
||||||
STAmount out;
|
{
|
||||||
|
in += rhs.in;
|
||||||
|
out += rhs.out;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAmounts& operator-=(TAmounts const& rhs)
|
||||||
|
{
|
||||||
|
in -= rhs.in;
|
||||||
|
out -= rhs.out;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIn in;
|
||||||
|
TOut out;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
template<class TIn, class TOut>
|
||||||
|
TAmounts<TIn, TOut> make_Amounts(TIn const& in, TOut const& out)
|
||||||
|
{
|
||||||
|
return TAmounts<TIn, TOut>(in, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
using Amounts = TAmounts<STAmount, STAmount>;
|
||||||
|
|
||||||
|
template<class TIn, class TOut>
|
||||||
bool
|
bool
|
||||||
operator== (Amounts const& lhs, Amounts const& rhs) noexcept
|
operator== (
|
||||||
|
TAmounts<TIn, TOut> const& lhs,
|
||||||
|
TAmounts<TIn, TOut> const& rhs) noexcept
|
||||||
{
|
{
|
||||||
return lhs.in == rhs.in && lhs.out == rhs.out;
|
return lhs.in == rhs.in && lhs.out == rhs.out;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
template<class TIn, class TOut>
|
||||||
bool
|
bool
|
||||||
operator!= (Amounts const& lhs, Amounts const& rhs) noexcept
|
operator!= (
|
||||||
|
TAmounts<TIn, TOut> const& lhs,
|
||||||
|
TAmounts<TIn, TOut> const& rhs) noexcept
|
||||||
{
|
{
|
||||||
return ! (lhs == rhs);
|
return ! (lhs == rhs);
|
||||||
}
|
}
|
||||||
@@ -101,6 +138,13 @@ public:
|
|||||||
explicit
|
explicit
|
||||||
Quality (Amounts const& amount);
|
Quality (Amounts const& amount);
|
||||||
|
|
||||||
|
/** Create a quality from the ratio of two amounts. */
|
||||||
|
template<class TIn, class TOut>
|
||||||
|
Quality (TOut const& out, TIn const& in)
|
||||||
|
: Quality (Amounts (toSTAmount (in),
|
||||||
|
toSTAmount (out)))
|
||||||
|
{}
|
||||||
|
|
||||||
/** Advances to the next higher quality level. */
|
/** Advances to the next higher quality level. */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
Quality&
|
Quality&
|
||||||
@@ -133,6 +177,21 @@ public:
|
|||||||
Amounts
|
Amounts
|
||||||
ceil_in (Amounts const& amount, STAmount const& limit) const;
|
ceil_in (Amounts const& amount, STAmount const& limit) const;
|
||||||
|
|
||||||
|
template<class TIn, class TOut>
|
||||||
|
TAmounts<TIn, TOut>
|
||||||
|
ceil_in (TAmounts<TIn, TOut> const& amount, TIn const& limit) const
|
||||||
|
{
|
||||||
|
if (amount.in <= limit)
|
||||||
|
return amount;
|
||||||
|
|
||||||
|
// Use the existing STAmount implementation for now, but consider
|
||||||
|
// replacing with code specific to IOUAMount and XRPAmount
|
||||||
|
Amounts stAmt (toSTAmount (amount.in), toSTAmount (amount.out));
|
||||||
|
STAmount stLim (toSTAmount (limit));
|
||||||
|
auto const stRes = ceil_in (stAmt, stLim);
|
||||||
|
return TAmounts<TIn, TOut> (toAmount<TIn> (stRes.in), toAmount<TOut> (stRes.out));
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the scaled amount with out capped.
|
/** Returns the scaled amount with out capped.
|
||||||
Math is avoided if the result is exact. The input is clamped
|
Math is avoided if the result is exact. The input is clamped
|
||||||
to prevent money creation.
|
to prevent money creation.
|
||||||
@@ -140,6 +199,21 @@ public:
|
|||||||
Amounts
|
Amounts
|
||||||
ceil_out (Amounts const& amount, STAmount const& limit) const;
|
ceil_out (Amounts const& amount, STAmount const& limit) const;
|
||||||
|
|
||||||
|
template<class TIn, class TOut>
|
||||||
|
TAmounts<TIn, TOut>
|
||||||
|
ceil_out (TAmounts<TIn, TOut> const& amount, TOut const& limit) const
|
||||||
|
{
|
||||||
|
if (amount.out <= limit)
|
||||||
|
return amount;
|
||||||
|
|
||||||
|
// Use the existing STAmount implementation for now, but consider
|
||||||
|
// replacing with code specific to IOUAMount and XRPAmount
|
||||||
|
Amounts stAmt (toSTAmount (amount.in), toSTAmount (amount.out));
|
||||||
|
STAmount stLim (toSTAmount (limit));
|
||||||
|
auto const stRes = ceil_out (stAmt, stLim);
|
||||||
|
return TAmounts<TIn, TOut> (toAmount<TIn> (stRes.in), toAmount<TOut> (stRes.out));
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns `true` if lhs is lower quality than `rhs`.
|
/** Returns `true` if lhs is lower quality than `rhs`.
|
||||||
Lower quality means the taker receives a worse deal.
|
Lower quality means the taker receives a worse deal.
|
||||||
Higher quality is better for the taker.
|
Higher quality is better for the taker.
|
||||||
@@ -151,6 +225,13 @@ public:
|
|||||||
return lhs.m_value > rhs.m_value;
|
return lhs.m_value > rhs.m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool
|
||||||
|
operator> (Quality const& lhs, Quality const& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.m_value < rhs.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
bool
|
bool
|
||||||
operator== (Quality const& lhs, Quality const& rhs) noexcept
|
operator== (Quality const& lhs, Quality const& rhs) noexcept
|
||||||
|
|||||||
@@ -312,6 +312,15 @@ amountFromJson (SField const& name, Json::Value const& v);
|
|||||||
bool
|
bool
|
||||||
amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource);
|
amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource);
|
||||||
|
|
||||||
|
// IOUAmount and XRPAmount define toSTAmount, defining this
|
||||||
|
// trivial conversion here makes writing generic code easier
|
||||||
|
inline
|
||||||
|
STAmount const&
|
||||||
|
toSTAmount (STAmount const& a)
|
||||||
|
{
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Observers
|
// Observers
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <ripple/protocol/SystemParameters.h>
|
#include <ripple/protocol/SystemParameters.h>
|
||||||
#include <beast/utility/Zero.h>
|
#include <beast/utility/Zero.h>
|
||||||
#include <boost/operators.hpp>
|
#include <boost/operators.hpp>
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -134,6 +135,27 @@ to_string (XRPAmount const& amount)
|
|||||||
return std::to_string (amount.drops ());
|
return std::to_string (amount.drops ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
XRPAmount
|
||||||
|
mulRatio (
|
||||||
|
XRPAmount const& amt,
|
||||||
|
std::uint32_t num,
|
||||||
|
std::uint32_t den,
|
||||||
|
bool roundUp)
|
||||||
|
{
|
||||||
|
using namespace boost::multiprecision;
|
||||||
|
int128_t const den128 (den);
|
||||||
|
int128_t const num128 (num);
|
||||||
|
int128_t const amt128 (amt.drops ());
|
||||||
|
auto const m = int128_t (amt.drops ()) * num;
|
||||||
|
auto r = m / den;
|
||||||
|
if (roundUp && r >= 0 && (m % den))
|
||||||
|
r += 1;
|
||||||
|
if (r > std::numeric_limits<std::int64_t>::max ())
|
||||||
|
throw std::overflow_error ("XRP mulRatio overflow");
|
||||||
|
return XRPAmount (r.convert_to<std::int64_t> ());
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns true if the amount does not exceed the initial XRP in existence. */
|
/** Returns true if the amount does not exceed the initial XRP in existence. */
|
||||||
inline
|
inline
|
||||||
bool isLegalAmount (XRPAmount const& amount)
|
bool isLegalAmount (XRPAmount const& amount)
|
||||||
|
|||||||
@@ -20,23 +20,24 @@
|
|||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/basics/contract.h>
|
#include <ripple/basics/contract.h>
|
||||||
#include <ripple/protocol/IOUAmount.h>
|
#include <ripple/protocol/IOUAmount.h>
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
void
|
/* The range for the mantissa when normalized */
|
||||||
IOUAmount::normalize ()
|
static std::int64_t const minMantissa = 1000000000000000ull;
|
||||||
{
|
static std::int64_t const maxMantissa = 9999999999999999ull;
|
||||||
/* The range for the exponent when normalized */
|
/* The range for the exponent when normalized */
|
||||||
static int const minExponent = -96;
|
static int const minExponent = -96;
|
||||||
static int const maxExponent = 80;
|
static int const maxExponent = 80;
|
||||||
|
|
||||||
/* The range for the mantissa when normalized */
|
void
|
||||||
static std::int64_t const minMantissa = 1000000000000000ull;
|
IOUAmount::normalize ()
|
||||||
static std::int64_t const maxMantissa = 9999999999999999ull;
|
{
|
||||||
|
|
||||||
if (mantissa_ == 0)
|
if (mantissa_ == 0)
|
||||||
{
|
{
|
||||||
*this = zero;
|
*this = zero;
|
||||||
@@ -244,4 +245,96 @@ to_string (IOUAmount const& amount)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOUAmount
|
||||||
|
mulRatio (
|
||||||
|
IOUAmount const& amt,
|
||||||
|
std::uint32_t num,
|
||||||
|
std::uint32_t den,
|
||||||
|
bool roundUp)
|
||||||
|
{
|
||||||
|
using namespace boost::multiprecision;
|
||||||
|
|
||||||
|
static std::vector<uint128_t> const logTable = []
|
||||||
|
{
|
||||||
|
std::vector<uint128_t> result;
|
||||||
|
result.reserve (30); // 2^96 is largest intermediate result size
|
||||||
|
uint128_t cur (1);
|
||||||
|
for (int i = 0; i < 30; ++i)
|
||||||
|
{
|
||||||
|
result.push_back (cur);
|
||||||
|
cur *= 10;
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
// Note: Returns -1 for v == 0
|
||||||
|
static auto log10Floor = [](uint128_t const& v)
|
||||||
|
{
|
||||||
|
auto const l = std::lower_bound (logTable.begin (), logTable.end (), v);
|
||||||
|
int index = std::distance (logTable.begin (), l);
|
||||||
|
if (*l != v)
|
||||||
|
--index;
|
||||||
|
return index;
|
||||||
|
};
|
||||||
|
static auto log10Ceil = [](uint128_t const& v)
|
||||||
|
{
|
||||||
|
auto const l = std::lower_bound (logTable.begin (), logTable.end (), v);
|
||||||
|
return int(std::distance (logTable.begin (), l));
|
||||||
|
};
|
||||||
|
static auto const fl64 =
|
||||||
|
log10Floor (std::numeric_limits<std::int64_t>::max ());
|
||||||
|
bool const neg = amt.mantissa () < 0;
|
||||||
|
uint128_t const den128 (den);
|
||||||
|
uint128_t const mul =
|
||||||
|
uint128_t (neg ? -amt.mantissa () : amt.mantissa ()) * uint128_t (num);
|
||||||
|
auto low = mul / den128;
|
||||||
|
uint128_t rem (mul - low * den128);
|
||||||
|
|
||||||
|
int exponent = amt.exponent ();
|
||||||
|
|
||||||
|
if (rem)
|
||||||
|
{
|
||||||
|
auto const roomToGrow = fl64 - log10Ceil (low);
|
||||||
|
if (roomToGrow > 0)
|
||||||
|
{
|
||||||
|
exponent -= roomToGrow;
|
||||||
|
low *= logTable[roomToGrow];
|
||||||
|
rem *= logTable[roomToGrow];
|
||||||
|
}
|
||||||
|
auto const addRem = rem / den128;
|
||||||
|
low += addRem;
|
||||||
|
rem = rem - addRem * den128;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasRem = bool(rem);
|
||||||
|
auto const mustShrink = log10Ceil (low) - fl64;
|
||||||
|
if (mustShrink > 0)
|
||||||
|
{
|
||||||
|
uint128_t const sav (low);
|
||||||
|
exponent += mustShrink;
|
||||||
|
low /= logTable[mustShrink];
|
||||||
|
if (!hasRem && roundUp)
|
||||||
|
hasRem = bool(sav - low * logTable[mustShrink]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t mantissa = low.convert_to<std::int64_t> ();
|
||||||
|
|
||||||
|
// normalize before rounding
|
||||||
|
if (neg)
|
||||||
|
mantissa *= -1;
|
||||||
|
|
||||||
|
IOUAmount result (mantissa, exponent);
|
||||||
|
|
||||||
|
if (roundUp && hasRem && !neg)
|
||||||
|
{
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return IOUAmount (minMantissa, minExponent);
|
||||||
|
}
|
||||||
|
return IOUAmount (result.mantissa() + 1, result.exponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user