-
Notifications
You must be signed in to change notification settings - Fork 302
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
dex: refactor internal indexing into ext traits #4188
Conversation
708c573
to
4e150c1
Compare
This is the general idea, probably needs workshopping but i think it's directionally what we want: a safe public DEX api with a small footprint, a private inner implementation that mediate state updates (with a second line of defense against invalid transitions), and a trust boundary behind which we have a variety of internal indices that only filter for relevant state transitions: ///
/// ┌─────────────────────────────────────────┐ public DEX component api
/// │ PositionManager │ that are wrappers around
/// │ public interface to the DEX component │ `update_position` and manage
/// │ │ │ the high-level side effects
/// └───────────────────┼─────────────────────┘ like ProtoEvent records
/// │
/// ▼
/// ┌─────────────────────────────────────────────┐
/// │ private Inner impl mediate state update │ update_position with
/// │ │ │ redundant checks
/// └─────────────────────┼───────────────────────┘
/// ■━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━■ trust
/// ▼ boundary
/// ┌────────────────────────────────────┐
/// │pub(super) trait Index { │
/// │ fn update_index(prev, new, id)│ update_index filters
/// │ │ │ for relevant state transitions
/// └──────────────────┼─────────────────┘ and deindex/index accordingly
/// ▼
/// ┌────────────────┐
/// │ internal Inner │ implementation details of the
/// └────────────────┘ indexing/deindexing logic
|
/// # Overview | ||
/// Given a directed trading pair `A -> B`, the index tracks the amount of | ||
/// liquidity available to convert the quote asset B, into a base asset A. |
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 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 think we could do this in #4193
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 think the entire index description could be workshopped, we should put some examples
match prev_state { | ||
Some(prev_state) => match (prev_state.state, new_state.state) { | ||
// We only want to update the index when we process active positions. | ||
(Opened, Closed) => {} | ||
(Opened, Opened) => {} | ||
_ => return Ok(()), | ||
}, | ||
None => {} | ||
} |
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.
Not sure this logic is correct. We do want to update the index when a new position is added, no? Can we refactor this into a match statement like
match (prev_state.map(|prev| prev.state), new_state.state) {
...
}
or (if it's cleaner) eliminate that match statement entirely in favor of something where we compute two values:
- a previous contribution to the total, to be subtracted (this is 0 if the position is newly opened)
- a current contribution to the total, to be added (this is 0 if the position is newly closed)
if both are 0 it can short circuit without state changes
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.
Oh, hmm, I guess this is sort of what it's doing before with the prev_a, prev_b
. I think it would be easier to understand if there wasn't a match statement here and the logic was "bail out if both prev and new amounts are 0".
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 reworked the structure based on your feedback, now we compute contributions upfront:
- compute
(prev_a, prev_b)
and clamp each value to zero if the position is closed/withdrawn - compute
(new_a, new_b)
and clamp each value to zero if the position is closed/withdrawn - short-circuit if all values are zero (e.g.
Closed -> Closed
or other "inactive" transitions)
crates/core/component/dex/src/component/position_manager/counter.rs
Outdated
Show resolved
Hide resolved
use anyhow::Result; | ||
use position::State::*; | ||
|
||
pub(super) trait PositionByInventoryIndex: StateWrite { |
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.
Can we add docs to this index describing where it's used? This is the index used for the position eviction logic, but there's another index of assets by inventory that's used for routing heuristics, and we should disambiguate between those.
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.
Agreed, though I'd prefer to document this with the eviction queue PR
Describe your changes
This PR:
Inner
position manager trait into submodules with crate visibilityupdate_position
to delegate indexing checks toupdate_*_index
methodsPositionManager::update_position
This PR contain changes to critical parts of the DEX engine internals.
Checklist before requesting a review
If this code contains consensus-breaking changes, I have added the "consensus-breaking" label. Otherwise, I declare my belief that there are not consensus-breaking changes, for the following reason: