-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: AMM swap rounding #5002
fix: AMM swap rounding #5002
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #5002 +/- ##
=========================================
- Coverage 70.9% 70.9% -0.0%
=========================================
Files 796 796
Lines 66727 66792 +65
Branches 10976 10996 +20
=========================================
+ Hits 47339 47378 +39
- Misses 19388 19414 +26
|
static_assert(alwaysFalse, "Unsupported type for toAmount"); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using concept
instead of the static_assert
here and other places?
template <typename T>
concept ValidAmount =
std::is_same_v<T, IOUAmount> ||
std::is_same_v<T, XRPAmount> ||
std::is_same_v<T, STAmount>;
template <ValidAmount T>
T
toMaxAmount(Issue const& issue)
{
...
}
I don't think max Number
is applicable, at least not in the context that toMaxAmount()
is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I got a compile error without the supporting Number
.
I don't object to the concept
, but I weakly prefer the code without it. I don't love that the is_same
is repeated in both the body of the function and the concept, and the concept isn't important for distinguishing between overloads. I'll change it if you or others feel strongly, but I think I prefer the non-concept version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It builds for me without Number
on OSX, Linux, and Windows.
I prefer concept
since it's clearly defines the type constraint. I don't feel strongly about it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hear you. I don't think this is worth spending too much time on. I'm going to keep it as is.
|
||
Number::setround(Number::upward); | ||
auto const numerator = pool.in * pool.out; | ||
auto const fee = getFee(tfee); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to always round upwards getFee()
and downward feeMult()
. The fee is added to the pool so we want always to maximize it's effect. Can have the default just in case it needs to be changed in some instances:
inline Number
getFee(std::uint16_t tfee, Number::rounding_mode rounding = Number::rounding_mode::upward)
{
if (auto const& rules = getCurrentTransactionRules();
rules && rules->enabled(fixAMMRounding))
{
saveNumberRoundMode rm(Number::setround(rounding));
return Number{tfee} / AUCTION_SLOT_FEE_SCALE_FACTOR;
}
return Number{tfee} / AUCTION_SLOT_FEE_SCALE_FACTOR;
}
inline Number
feeMult(std::uint16_t tfee, Number::rounding_mode rounding = Number::rounding_mode::downward)
{
if (auto const& rules = getCurrentTransactionRules();
rules && rules->enabled(fixAMMRounding))
{
saveNumberRoundMode rm(Number::setround(rounding));
return 1 - getFee(tfee);
}
return 1 - getFee(tfee);
}
BEAST_EXPECT(ammAlice.expectBalances( | ||
XRP(11'000), USD(11'000), IOUAmount{10'999'890, 0})); | ||
}); | ||
testAMM( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and a few other places the tests are executed twice with/without fixAMMRounding
and there is no change to the tests with fixAMMRounding
. Should we limit this to only the tests that have different results with fixAMMRounding
? This impacts the run-time of the tests. testAMM()
can be changed to take a vector of features and could also add a helper function to iterate over a vector of features in cases where testAMM()
is not used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, but I would like to make CurrentTransactionRulesGuard
not copyable either now or in the near future. All it needs is deleted copy members. We already do not copy it, so this won't break anything.
class CurrentTransactionRulesGuard | ||
{ | ||
public: | ||
explicit CurrentTransactionRulesGuard(Rules r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class should not be CopyConstructible nor CopyAssignable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, agreed, thanks! Fixed in 94bbc9c8a9 [fold] CurrentTransactionRulesGuard should not be copyable or assignable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 LGTM. I left one note that might be a small improvement for future maintainability. But, in general, it looks like it should do the job.
src/ripple/ledger/impl/View.cpp
Outdated
if (auto const& rules = getCurrentTransactionRules(); | ||
rules && rules->enabled(fixAMMRounding)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are now two sources of "truth" regarding the Rules
: the Rules
in the current ledger or the Rules
supplied by getCurrentTransactionRules()
. And, interestingly, those two perspectives are only in alignment if the code being executed is inside the scope of a transactor. Outside the scope of a transactor, getCurrentTransactionRules()
returns a nullopt_t
.
I think the safest approach everywhere in this file is to call view.rules().enabled()
to get the Rules
that are explicitly associated with the ledger that was explicitly passed in. That way the code that is likely to be copied and pasted will work in both ApplyView
s and ReadView
s. So I suggest changing these lines to:
if (view.rules().enabled(fixAMMRounding))
But that's just looking forward to when this is copied and pasted within this file. The current implementation should also work just fine in this particular function.
e751e72
to
3cfc52f
Compare
It can be difficult to make transaction breaking changes to low level code because the low level code does not have access to a ledger and the current activated amendments in that ledger (the "rules"). This patch adds global access to the current ledger rules as a `std::optional`. If the optional is not seated, then there is no active transaction.
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
The AMM has an invariant for swaps where: new_balance_1*new_balance_2 >= old_balance_1*old_balance_2 Due to rounding, this invariant could sometimes be violated (although by very small amounts). This patch introduces an amendment `fixAMMRounding` that changes the rounding to always favor the AMM. Doing this should maintain the invariant. Co-authored-by: Bronek Kozicki Co-authored-by: thejohnfreeman
High Level Overview of Change
fix amendment: AMM swap should honor invariants:
The AMM has an invariant for swaps where:
Due to rounding, this invariant could sometimes be violated (although by very small amounts).
This patch introduces an amendment
fixAMMRounding
that changes the rounding to always favor the AMM. Doing this should maintain the invariant.Type of Change
.gitignore
, formatting, dropping support for older tooling)