From 53bf5e7f364f4a11b647b8cfccc5664404bc7adb Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Tue, 8 Apr 2014 17:45:01 -0700 Subject: [PATCH] New classes and types for handling asset amounts: * Quality opaque type for order book quality * Amount replacement for STAmount * Amounts, in/out amount pair for offers * 'core' namespace with type aliases for Ripple primitives. --- Builds/VisualStudio2013/RippleD.vcxproj | 8 + .../VisualStudio2013/RippleD.vcxproj.filters | 27 ++ src/ripple_app/book/Amount.h | 330 ++++++++++++++++++ src/ripple_app/book/Amounts.h | 66 ++++ src/ripple_app/book/Quality.h | 198 +++++++++++ src/ripple_app/book/Types.h | 63 ++++ src/ripple_app/book/tests/Quality.test.cpp | 249 +++++++++++++ src/ripple_app/ripple_app_pt4.cpp | 2 + 8 files changed, 943 insertions(+) create mode 100644 src/ripple_app/book/Amount.h create mode 100644 src/ripple_app/book/Amounts.h create mode 100644 src/ripple_app/book/Quality.h create mode 100644 src/ripple_app/book/Types.h create mode 100644 src/ripple_app/book/tests/Quality.test.cpp diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index a0c8469f1f..ed667ed46b 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -820,6 +820,10 @@ true + + true + true + true true @@ -2479,6 +2483,10 @@ + + + + diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index c935560836..1104a47d64 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -319,6 +319,15 @@ {dcb7c75c-4f1d-486c-8079-52dc43644ae6} + + {1aa56407-a927-42be-862b-cd5324b4d63b} + + + {56248509-436d-4034-ab4e-64afbb532418} + + + {28b72c9f-02e3-4b57-9386-957478e1f0b7} + @@ -1500,6 +1509,12 @@ [2] Old Ripple\ripple_app\tx + + [1] Ripple\common\tests + + + [2] Old Ripple\ripple_app\book\tests + @@ -3063,6 +3078,18 @@ [2] Old Ripple\ripple_app\tx + + [2] Old Ripple\ripple_app\book + + + [2] Old Ripple\ripple_app\book + + + [2] Old Ripple\ripple_app\book + + + [2] Old Ripple\ripple_app\book + diff --git a/src/ripple_app/book/Amount.h b/src/ripple_app/book/Amount.h new file mode 100644 index 0000000000..5b5bf60be3 --- /dev/null +++ b/src/ripple_app/book/Amount.h @@ -0,0 +1,330 @@ +//------------------------------------------------------------------------------ +/* + 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_CORE_AMOUNT_H_INCLUDED +#define RIPPLE_CORE_AMOUNT_H_INCLUDED + +#include "../../ripple_data/protocol/SerializedObject.h" + +#include "../../beast/beast/utility/noexcept.h" +#include "../../beast/beast/cxx14/type_traits.h" // + +//------------------------------------------------------------------------------ + +struct Zero +{ + Zero() + { + } +}; + +namespace { +static Zero const zero; +} + +namespace detail { +namespace Zero_helpers { +template +int +get_signum (T const& t) noexcept +{ + return signum(t); +} +} +} + +/** Handle operators where T is on the left side using signum. */ +template + +bool operator==(T const& t, Zero) +{ + return detail::Zero_helpers::get_signum(t) == 0; +} + +template +bool operator!=(T const& t, Zero) +{ + return detail::Zero_helpers::get_signum(t) != 0; +} + +template +bool operator>(T const& t, Zero) +{ + return detail::Zero_helpers::get_signum(t) > 0; +} + +template +bool operator>=(T const& t, Zero) +{ + return detail::Zero_helpers::get_signum(t) >= 0; +} + +template +bool operator<(T const& t, Zero) +{ + return detail::Zero_helpers::get_signum(t) < 0; +} + +template +bool operator<=(T const& t, Zero) +{ + return detail::Zero_helpers::get_signum(t) <= 0; +} + + +/** Handle operators where T is on the right side by reversing the operation, + so that T is on the left side. + */ +template +bool operator==(Zero, T const& t) +{ + return t == zero; +} + +template +bool operator!=(Zero, T const& t) +{ + return t != zero; +} + +template +bool operator>(Zero, T const& t) +{ + return t < zero; +} + +template +bool operator>=(Zero, T const& t) +{ + return t <= zero; +} + +template +bool operator<(Zero, T const& t) +{ + return t > zero; +} + +template +bool operator<=(Zero, T const& t) +{ + return t >= zero; +} + +/** Default implementation calls the method on the class. + Alternatively, signum may be overloaded in the same namespace and found + via argument dependent lookup. +*/ +template +auto signum(T const& t) -> decltype(t.signum()) { + return t.signum(); +} + +//------------------------------------------------------------------------------ + +namespace ripple { +namespace core { + +/** Custom floating point asset amount. + The "representation" may be integral or non-integral. For integral + representations, the exponent is always zero and the value held in the + mantissa is an exact quantity. +*/ +class AmountType +{ +private: + std::uint64_t m_mantissa; + int m_exponent; + bool m_negative; + bool m_integral; + + AmountType (std::uint64_t mantissa, + int exponent, bool negative, bool integral) + : m_mantissa (mantissa) + , m_exponent (exponent) + , m_negative (negative) + , m_integral (integral) + { + } + +public: + /** Default construction. + The value is uninitialized. + */ + AmountType() noexcept + { + } + + /** Construct from an integer. + The representation is set to integral. + */ + /** @{ */ + template + AmountType (Integer value, + std::enable_if_t ::value>* = 0) noexcept + : m_mantissa (value) + , m_exponent (0) + , m_negative (value < 0) + , m_integral (true) + { + static_assert (std::is_integral::value, + "Cannot construct from non-integral type."); + } + + template + AmountType (Integer value, + std::enable_if_t ::value>* = 0) noexcept + : m_mantissa (value) + , m_exponent (0) + , m_negative (false) + { + static_assert (std::is_integral::value, + "Cannot construct from non-integral type."); + } + /** @} */ + + /** Assign the value zero. + The representation is preserved. + */ + AmountType& + operator= (Zero) noexcept + { + m_mantissa = 0; + // VFALCO Why -100? + // "We have to use something in range." + // "This makes zero the smallest value." + m_exponent = m_integral ? 0 : -100; + m_exponent = 0; + m_negative = false; + return *this; + } + + /** Returns the value in canonical format. */ + AmountType + normal() const noexcept + { + if (m_integral) + { + AmountType result; + if (m_mantissa == 0) + { + result.m_exponent = 0; + result.m_negative = false; + } + return result; + } + return AmountType(); + } + + // + // Comparison + // + + int + signum() const noexcept + { + if (m_mantissa == 0) + return 0; + return m_negative ? -1 : 1; + } + + bool + operator== (AmountType const& other) const noexcept + { + return + m_negative == other.m_negative && + m_mantissa == other.m_mantissa && + m_exponent == other.m_exponent; + } + + bool + operator!= (AmountType const& other) const noexcept + { + return ! (*this == other); + } + + bool + operator< (AmountType const& other) const noexcept + { + return false; + } + + bool + operator>= (AmountType const& other) const noexcept + { + return ! (*this < other); + } + + bool + operator> (AmountType const& other) const noexcept + { + return other < *this; + } + + bool + operator<= (AmountType const& other) const noexcept + { + return ! (other < *this); + } + + // + // Arithmetic + // + + AmountType + operator-() const noexcept + { + return AmountType (m_mantissa, m_exponent, ! m_negative, m_integral); + } + + // + // Output + // + + std::ostream& + operator<< (std::ostream& os) + { + int const sig (signum()); + + if (sig == 0) + return os << "0"; + else if (sig < 0) + os << "-"; + + if (m_integral) + return os << m_mantissa; + + if (m_exponent != 0 && (m_exponent < -25 || m_exponent > -5)) + return os << m_mantissa << "e" << m_exponent; + + //if (m_exponent > 0) + // return os << + + return os; + } +}; + +//------------------------------------------------------------------------------ + +typedef STAmount Amount; + +} +} + +#endif diff --git a/src/ripple_app/book/Amounts.h b/src/ripple_app/book/Amounts.h new file mode 100644 index 0000000000..709b337bc9 --- /dev/null +++ b/src/ripple_app/book/Amounts.h @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +/* + 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_CORE_AMOUNTS_H_INCLUDED +#define RIPPLE_CORE_AMOUNTS_H_INCLUDED + +#include "Amount.h" + +namespace ripple { +namespace core { + +struct Amounts +{ + Amounts() = default; + + Amounts (Amount const& in_, Amount const& out_) + : in (in_) + , out (out_) + { + } + + /** Returns `true` if either quantity is not positive. */ + bool + empty() const noexcept + { + return ! in.isPositive() || ! out.isPositive(); + } + + Amount in; + Amount out; +}; + +inline +bool +operator== (Amounts const& lhs, Amounts const& rhs) noexcept +{ + return lhs.in == rhs.in && lhs.out == rhs.out; +} + +inline +bool +operator!= (Amounts const& lhs, Amounts const& rhs) noexcept +{ + return ! (lhs == rhs); +} + +} +} + +#endif diff --git a/src/ripple_app/book/Quality.h b/src/ripple_app/book/Quality.h new file mode 100644 index 0000000000..d1d51fa9c2 --- /dev/null +++ b/src/ripple_app/book/Quality.h @@ -0,0 +1,198 @@ +//------------------------------------------------------------------------------ +/* + 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_CORE_QUALITY_H_INCLUDED +#define RIPPLE_CORE_QUALITY_H_INCLUDED + +#include "Amount.h" +#include "Amounts.h" + +#include +#include +#include +#include + +namespace ripple { +namespace core { + +/** Represents the logical ratio of output currency to input currency. + Internally this is stored using a custom floating point representation, + as the inverse of the ratio, so that quality will be descending in + a sequence of actual values that represent qualities. +*/ +class Quality +{ +public: + // Type of the internal representation. Higher qualities + // have lower unsigned integer representations. + typedef std::uint64_t value_type; + +private: + value_type m_value; + +public: + Quality() = default; + + explicit + Quality (std::uint64_t value) + : m_value (value) + { + } + + /** Create a quality from the ratio of two amounts. */ + explicit + Quality (Amounts const& amount) + : m_value (Amount::getRate (amount.out, amount.in)) + { + } + + /** Advances to the next higher quality level. */ + /** @{ */ + Quality& + operator++() + { + assert (m_value > 0); + --m_value; + return *this; + } + + Quality + operator++ (int) + { + Quality prev (*this); + --*this; + return prev; + } + /** @} */ + + /** Advances to the next lower quality level. */ + /** @{ */ + Quality& + operator--() + { + assert (m_value < std::numeric_limits::max()); + ++m_value; + return *this; + } + + Quality + operator-- (int) + { + Quality prev (*this); + ++*this; + return prev; + } + /** @} */ + + /** Returns `true` if lhs is lower quality than `rhs`. + Lower quality means the taker receives a worse deal. + Higher quality is better for the taker. + */ + friend + bool + operator< (Quality const& lhs, Quality const& rhs) noexcept + { + 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 + std::ostream& + operator<< (std::ostream& os, Quality const& quality) + { + os << quality.m_value; + return os; + } + + /** Returns the quality as Amount. */ + Amount + rate() const + { + return Amount::setRate (m_value); + } + + /** Returns the scaled amount with in capped. + Math is avoided if the result is exact. The output is clamped + to prevent money creation. + */ + Amounts + ceil_in (Amounts const& amount, Amount const& limit) const + { + if (amount.in > limit) + { + // VFALCO TODO make mulRound avoid math when v2==one +#if 0 + Amounts result (limit, Amount::mulRound ( + limit, rate(), amount.out, true)); +#else + Amounts result (limit, Amount::divRound ( + limit, rate(), amount.out, true)); +#endif + // Clamp out + if (result.out > amount.out) + result.out = amount.out; + return result; + } + + return amount; + } + + /** Returns the scaled amount with out capped. + Math is avoided if the result is exact. The input is clamped + to prevent money creation. + */ + Amounts + ceil_out (Amounts const& amount, Amount const& limit) const + { + if (amount.out > limit) + { + // VFALCO TODO make divRound avoid math when v2==one +#if 0 + Amounts result (Amount::divRound ( + limit, rate(), amount.in, true), limit); +#else + Amounts result (Amount::mulRound ( + limit, rate(), amount.in, true), limit); +#endif + // Clamp in + if (result.in > amount.in) + result.in = amount.in; + return result; + } + return amount; + } +}; + +inline +bool +operator!= (Quality const& lhs, Quality const& rhs) noexcept +{ + return ! (lhs == rhs); +} + +} +} + +#endif diff --git a/src/ripple_app/book/Types.h b/src/ripple_app/book/Types.h new file mode 100644 index 0000000000..a6a85f68b9 --- /dev/null +++ b/src/ripple_app/book/Types.h @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +/* + 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_CORE_TYPES_H_INCLUDED +#define RIPPLE_CORE_TYPES_H_INCLUDED + +#include "../ledger/LedgerEntrySet.h" +#include "../../ripple/types/api/RippleAssets.h" +#include "../../ripple/types/api/UInt160.h" + +#include +#include + +namespace ripple { +namespace core { + +/** A mutable view that overlays an immutable ledger to track changes. */ +typedef LedgerEntrySet LedgerView; + +/** Identifies an account. */ +typedef uint160 Account; + +/** Asset identifiers. */ +typedef RippleCurrency Currency; +typedef RippleIssuer Issuer; +typedef RippleAsset Asset; +typedef RippleAssetRef AssetRef; + +/** Uniquely identifies an order book. */ +typedef RippleBook Book; +typedef RippleBookRef BookRef; + +/** A clock representing network time. + This measures seconds since the Ripple epoch as seen + by the ledger close clock. +*/ +class Clock // : public abstract_clock +{ +public: + typedef std::uint32_t time_point; + typedef std::chrono::seconds duration; +}; + +} +} + +#endif diff --git a/src/ripple_app/book/tests/Quality.test.cpp b/src/ripple_app/book/tests/Quality.test.cpp new file mode 100644 index 0000000000..18b2bc3980 --- /dev/null +++ b/src/ripple_app/book/tests/Quality.test.cpp @@ -0,0 +1,249 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#include "../Quality.h" + +#include "../../../beast/beast/unit_test/suite.h" +#include "../../../beast/beast/cxx14/type_traits.h" + +namespace ripple { +namespace core { + +class Quality_test : public beast::unit_test::suite +{ +public: + // Create a raw, non-integral amount from mantissa and exponent + Amount + static raw (std::uint64_t mantissa, int exponent) + { + return Amount (uint160(3), uint160(3), mantissa, exponent); + } + + template + static + Amount + amount (Integer integer, + std::enable_if_t ::value>* = 0) + { + static_assert (std::is_integral ::value, ""); + return Amount (integer, false); + } + + template + static + Amount + amount (Integer integer, + std::enable_if_t ::value>* = 0) + { + static_assert (std::is_integral ::value, ""); + if (integer < 0) + return Amount (-integer, true); + return Amount (integer, false); + } + + template + static + Amounts + amounts (In in, Out out) + { + return Amounts (amount(in), amount(out)); + } + + template + void + ceil_in (Quality const& q, + In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected) + { + auto expect_result (amounts (in_expected, out_expected)); + auto actual_result (q.ceil_in (amounts(in, out), amount(limit))); + + expect (actual_result == expect_result); + } + + template + void + ceil_out (Quality const& q, + In1 in, Out1 out, Int limit, In2 in_expected, Out2 out_expected) + { + auto const expect_result (amounts (in_expected, out_expected)); + auto const actual_result (q.ceil_out (amounts(in, out), amount(limit))); + + expect (actual_result == expect_result); + } + + void + test_ceil_in () + { + testcase ("ceil_in"); + + { + // 1 in, 1 out: + Quality q (Amounts (amount(1), amount(1))); + + ceil_in (q, + 1, 1, // 1 in, 1 out + 1, // limit: 1 + 1, 1); // 1 in, 1 out + + ceil_in (q, + 10, 10, // 10 in, 10 out + 5, // limit: 5 + 5, 5); // 5 in, 5 out + + ceil_in (q, + 5, 5, // 5 in, 5 out + 10, // limit: 10 + 5, 5); // 5 in, 5 out + } + + { + // 1 in, 2 out: + Quality q (Amounts (amount(1), amount(2))); + + ceil_in (q, + 40, 80, // 40 in, 80 out + 40, // limit: 40 + 40, 80); // 40 in, 20 out + + ceil_in (q, + 40, 80, // 40 in, 80 out + 20, // limit: 20 + 20, 40); // 20 in, 40 out + + ceil_in (q, + 40, 80, // 40 in, 80 out + 60, // limit: 60 + 40, 80); // 40 in, 80 out + } + + { + // 2 in, 1 out: + Quality q (Amounts (amount(2), amount(1))); + + ceil_in (q, + 40, 20, // 40 in, 20 out + 20, // limit: 20 + 20, 10); // 20 in, 10 out + + ceil_in (q, + 40, 20, // 40 in, 20 out + 40, // limit: 40 + 40, 20); // 40 in, 20 out + + ceil_in (q, + 40, 20, // 40 in, 20 out + 50, // limit: 40 + 40, 20); // 40 in, 20 out + } + } + + void + test_ceil_out () + { + testcase ("ceil_out"); + + { + // 1 in, 1 out: + Quality q (Amounts (amount(1),amount(1))); + + ceil_out (q, + 1, 1, // 1 in, 1 out + 1, // limit 1 + 1, 1); // 1 in, 1 out + + ceil_out (q, + 10, 10, // 10 in, 10 out + 5, // limit 5 + 5, 5); // 5 in, 5 out + + ceil_out (q, + 10, 10, // 10 in, 10 out + 20, // limit 20 + 10, 10); // 10 in, 10 out + } + + { + // 1 in, 2 out: + Quality q (Amounts (amount(1),amount(2))); + + ceil_out (q, + 40, 80, // 40 in, 80 out + 40, // limit 40 + 20, 40); // 20 in, 40 out + + ceil_out (q, + 40, 80, // 40 in, 80 out + 80, // limit 80 + 40, 80); // 40 in, 80 out + + ceil_out (q, + 40, 80, // 40 in, 80 out + 100, // limit 100 + 40, 80); // 40 in, 80 out + } + + { + // 2 in, 1 out: + Quality q (Amounts (amount(2),amount(1))); + + ceil_out (q, + 40, 20, // 40 in, 20 out + 20, // limit 20 + 40, 20); // 40 in, 20 out + + ceil_out (q, + 40, 20, // 40 in, 20 out + 40, // limit 40 + 40, 20); // 40 in, 20 out + + ceil_out (q, + 40, 20, // 40 in, 20 out + 10, // limit 10 + 20, 10); // 20 in, 10 out + } + } + + void + test_raw() + { + { + Quality q (0x5d048191fb9130daull); // 126836389.7680090 + Amounts const value ( + amount(349469768), // 349.469768 XRP + raw (2755280000000000ull, -15)); // 2.75528 + Amount const limit ( + raw (4131113916555555, -16)); // .4131113916555555 + Amounts const result (q.ceil_out (value, limit)); + expect (! result.in.isZero()); + } + } + + void + run() + { + test_ceil_in (); + test_ceil_out (); + test_raw(); + } +}; + +BEAST_DEFINE_TESTSUITE_MANUAL(Quality,core,ripple); + +} +} diff --git a/src/ripple_app/ripple_app_pt4.cpp b/src/ripple_app/ripple_app_pt4.cpp index 5b1eaa8397..8b0bb9ce05 100644 --- a/src/ripple_app/ripple_app_pt4.cpp +++ b/src/ripple_app/ripple_app_pt4.cpp @@ -37,3 +37,5 @@ #include "tx/Transaction.cpp" #include "tx/TransactionEngine.cpp" #include "tx/TransactionMeta.cpp" + +#include "book/tests/Quality.test.cpp"