If the mantissas of two non-native amounts differ by less than 10, then
subtracting them leaves a result of zero. This can cause situations
where `a>b`, yet `a-b == 0`.
One consequence of this is unfunded offers were incorrectly left in
order books. The code would check if the offer would be
consumed (`amount in offer > amount needed`), assume it wouldn't be,
yet when `amount needed` was subtracted from `amount in offer` the
result was zero and the offer was unfunded. This unfunded offer
incorrectly remained on the order book.
This patch fixes this bug.
The Ripple protocol represent transfer rates and trust line
qualities as fractions of one billion. For example, a transfer
rate of 1% is represented as 1010000000.
Previously, such rates where represented either as std::uint32_t
or std::uint64_t. Other, nominally related types, also used an
integral representation and could be unintentionally substituted.
The new Rate class addresses this by providing a simple, type
safe alternative which also helps make the code self-documenting
since arithmetic operations now can be clearly understood to
involve the scaling of an amount by a rate.
Before this change, the deferred credits algorithm took the current
balance and subtracted the recorded credits. Conceptually, this is the
same as taking the original balance, adding all the credits,
subtracting all the debits, and subtracting all the credits. The new
algorithm records the original balance and subtracts the debits. This
prevents errors that occur when the original balance and the recorded
credits have large differences in magnitude.
Additionally, XRP credits were recorded incorrectly in the deferred
credits table (the line was between the sender and receiver, rather than
the root account).
Payments do not remove unfunded and expired offers when a payment
fails. However, offer crossing is now using the payment engine and needs
to know what offers were found in a removable state, even on failure.
A computation like: `amount_remaining = amount_wanted - amount_got`, can
leave `amount_remaining == 0` without `amount_wanted == amount_got`.
This happens if the amounts differ by less than the smallest
representable value. Fix BookStep to handle this case.
Replace Journal public data members with member function accessors
in order to make Journal lighter weight. The change makes a
Journal cheaper to pass by value.
Also add missing stream checks (e.g., calls to JLOG) to avoid
text processing that ultimately will not be stored in the log.
Add a new algorithm for finding the liquidity in a payment path. There
is still a reverse and forward pass, but the forward pass starts at the
limiting step rather than the payment source. This insures the limiting
step is completely consumed rather than potentially leaving a 'dust'
amount in the forward pass.
Each step in a payment is either a book step, a direct step (account to
account step), or an xrp endpoint. Each step in the existing
implementation is a triple, where each element in the triple is either
an account of a book, for a total of eight step types.
Since accounts are considered in pairs, rather than triples, transfer
fees are handled differently. In V1 of payments, in the payment path
A -> gw ->B, if A redeems to gw, and gw issues to B, a transfer fee is
changed. In the new code, a transfer fee is changed even if A issues to
gw.