Skip to content

Commit

Permalink
[fold] add precision loss
Browse files Browse the repository at this point in the history
  • Loading branch information
dangell7 committed Dec 2, 2024
1 parent 43546f7 commit d4c056a
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 111 deletions.
42 changes: 42 additions & 0 deletions include/xrpl/protocol/STAmount.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,48 @@ isXRP(STAmount const& amount)
return amount.native();
}

/** returns true if adding or subtracting results in less than or equal to
* 0.01% precision loss **/
inline bool
isAddable(STAmount const& amt1, STAmount const& amt2)
{
// special case: adding anything to zero is always fine
if (amt1 == beast::zero || amt2 == beast::zero)
return true;

// special case: adding two xrp amounts together.
// this is just an overflow check
if (isXRP(amt1) && isXRP(amt2))
{
XRPAmount A = (amt1.signum() == -1 ? -(amt1.xrp()) : amt1.xrp());
XRPAmount B = (amt2.signum() == -1 ? -(amt2.xrp()) : amt2.xrp());

XRPAmount finalAmt = A + B;
return (finalAmt >= A && finalAmt >= B);
}

static const STAmount one{IOUAmount{1, 0}, noIssue()};
static const STAmount maxLoss{IOUAmount{1, -4}, noIssue()};

STAmount A = amt1;
STAmount B = amt2;

if (isXRP(A))
A = STAmount{IOUAmount{A.xrp().drops(), -6}, noIssue()};

if (isXRP(B))
B = STAmount{IOUAmount{B.xrp().drops(), -6}, noIssue()};

A.setIssue(noIssue());
B.setIssue(noIssue());

STAmount lhs = divide((A - B) + B, A, noIssue()) - one;
STAmount rhs = divide((B - A) + A, B, noIssue()) - one;

return ((rhs.negative() ? -rhs : rhs) + (lhs.negative() ? -lhs : lhs)) <=
maxLoss;
}

// Since `canonicalize` does not have access to a ledger, this is needed to put
// the low-level routine stAmountCanonicalize on an amendment switch. Only
// transactions need to use this switchover. Outside of a transaction it's safe
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/TER.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ enum TECcodes : TERUnderlyingType {
tecARRAY_TOO_LARGE = 191,
tecLOCKED = 192,
tecBAD_CREDENTIALS = 193,
tecPRECISION_LOSS = 194,
};

//------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/libxrpl/protocol/TER.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ transResults()
MAKE_ERROR(tecARRAY_TOO_LARGE, "Array is too large."),
MAKE_ERROR(tecLOCKED, "Fund is locked."),
MAKE_ERROR(tecBAD_CREDENTIALS, "Bad credentials."),
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),

MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
Expand Down
Loading

0 comments on commit d4c056a

Please sign in to comment.