Skip to content
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

feat(run-protocol): liquidate serially #4931

Merged
merged 6 commits into from
Mar 31, 2022

Conversation

turadg
Copy link
Member

@turadg turadg commented Mar 26, 2022

closes: #4750
refs: #XXXX

Description

Restores liquidateAndRemove promise from #4715 but changes the high-water-mark case to liquidate serially instead of starting them all at once in parallel.

For the liquidateAll case it continues start them all at once in parallel, assuming that that would maximize the throughput and efficiency is not a concern for that case.

Security Considerations

Reduces dependence on durable state.

Documentation Considerations

--

Testing Considerations

Existing unit tests.

@turadg turadg requested a review from dtribble March 26, 2022 16:45
@turadg turadg requested a review from Chris-Hibbert as a code owner March 26, 2022 16:45
Copy link
Member

@dtribble dtribble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great except for a critical await error

quoteRatioPlusMargin,
)) {
// eslint-disable-next-line no-await-in-loop -- We want each liquidation to happen in a separate turn
await liquidateAndRemove([key, vault]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually exactly the scenario that the await rule is designed to prevent, so I don't think this is an allowable exception. If entriesPrioritizedGTE returns an empty iteration, then line 229 will execute in the same turn, whereas if it does not, it would execute in a different turn.

@turadg turadg force-pushed the 4750-simplify-liquidation-queuing branch from 2f64e5e to 3f15daf Compare March 30, 2022 17:54
@turadg turadg requested a review from dtribble March 30, 2022 22:22
Comment on lines -2303 to -2367
// expect Alice to be liquidated because her collateral is too low.
aliceUpdate = await E(aliceNotifier).getUpdateSince();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Chris-Hibbert can you confirm these test changes are legit?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This update isn't used. It seems fine to drop it.

Copy link
Contributor

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you confirm these test changes are legit?

They shouldn't break the test. They change the test's behavior if the code being tested stops working, but they should reveal the same faults.

)
.then(() => {
assert(prioritizedVaults);
prioritizedVaults?.removeVault(key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need optional chaining when it has just asserted that prioritizedVaults is non-null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably a result of refactoring. corrected.

Comment on lines -2303 to -2367
// expect Alice to be liquidated because her collateral is too low.
aliceUpdate = await E(aliceNotifier).getUpdateSince();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This update isn't used. It seems fine to drop it.

t.is(bobUpdate.value.vaultState, Phase.LIQUIDATED);

// No change for Alice
aliceUpdate = await E(aliceNotifier).getUpdateSince(); // can't use updateCount because there's no newer update
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateCount is optional. You don't need to justify not including it. Not including it means "I want the current state, even if it hasn't changed."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to include it in the other places or the update would come back before the liquidation processor settled. There are more promise resolutions now with "liquidate one at a time".

I actually think we should make a habit of including the updateCount so that you have a guarantee that you're getting a new state. If you don't expect a new state then don't ask for it and if you do then the test should fail if it's not available.

I even think it might be worth a helper wrapper around this notifier/response pair so you could have,

const aliceAfterLiquidation = await alicesUpdates.next();

(it would do the updateCount stuff itself to ensure you're getting a new update)

t.deepEqual(aliceUpdate.value.debtSnapshot.debt, aliceRunDebtLevel);

await manualTimer.tick();
// price levels changed and interest was charged.

// expect Alice to be liquidated because her collateral is too low.
aliceUpdate = await E(aliceNotifier).getUpdateSince();
aliceUpdate = await E(aliceNotifier).getUpdateSince(aliceUpdate.updateCount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding updateCount to these calls is acceptable, though I'm not sure it's an improvement.

Using getUpdateSince without an argument can be more robust in a test because the test won't wait in vain when something changes. It'll return the existing state, which should be tested.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spoke to this above but for review hygiene: it's better to be more explicit about whether a new state is expected, especially due to the interleaving of async calls that are common in our code.

@turadg turadg added the automerge:squash Automatically squash merge label Mar 31, 2022
@mergify mergify bot merged commit 91a62a5 into master Mar 31, 2022
@mergify mergify bot deleted the 4750-simplify-liquidation-queuing branch March 31, 2022 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:squash Automatically squash merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simplify liquidation queuing
3 participants