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

BSIP31-34 market engine improvements #829

Merged
merged 29 commits into from
Apr 12, 2018
Merged

Conversation

abitmore
Copy link
Member

@abitmore abitmore commented Apr 7, 2018

For:
* #338 Margin call order fills at price of matching limit_order
* #343 Inconsistent sorting of call orders between matching against a limit order and a force settle order
* #453 Multiple limit order and call order matching issue
* #606 Undercollateralized short positions should be called regardless of asks
Be consistent with check_call_orders().
@abitmore abitmore added this to the 201805 - Consensus Changing Release milestone Apr 7, 2018
{
wlog( "Cull_small issue occurred at block #${block}", ("block",head_block_num()) );
limit_itr = next_limit_itr;
if( filled_limit ) ++limit_itr;
Copy link
Member Author

@abitmore abitmore Apr 7, 2018

Choose a reason for hiding this comment

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

Note:

  • the code block here, including ++limit_itr here and below, has been refactored in a later commit, we'll need to review again.
  • there are test cases about the cull_small issue after hard fork in commits for BSIP35.

const asset_object& a = *itr;
++itr;
// be here, next_maintenance_time should have been updated already
db.check_call_orders( a, true, false ); // allow black swan, and call orders are taker
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps skip over PM's here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Whether to skip over PM's here, the only logic difference might be the check_black_swan() call in check_call_orders().

Since we didn't fix #460 in this release (no BSIP for it so far), PM's will still suffer black swan events when there is a price feed change or matching logic change.

Although we didn't update call_prices of PM's, but we changed logic in check_black_swan() to check with MSSP, which is possible to trigger a black swan event. So the outcome is different if skip over PM's here.

I'd suggest we trigger black swan events here (if there would be some) to be consistent (rather than triggering on a new but same price feed).

Copy link
Member Author

Choose a reason for hiding this comment

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

Perhaps keep the old logic for PM's, don't trigger black swan event when there is no matching limit order?

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 we agreed that #460 is a bug and doesn't need a BSIP.
We could fix #460 quickly by adding a HF-protected check in check_for_black_swan, then don't need to skip here.

Copy link
Member Author

Choose a reason for hiding this comment

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

My opinion on #460 is here: #460 (comment). Aka not really a bug and not a quick fix to me.

So my recommendation in this release is to let PMs (still) have same behavior (on black swan events) as other MPAs, that said, we changed behavior of other MPAs, which will affect PMs as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

assert( settle_price.base.asset_id == limit_itr->sell_price.base.asset_id );
highest = std::max( limit_itr->sell_price, settle_price );
FC_ASSERT( highest.base.asset_id == limit_itr->sell_price.base.asset_id );
highest = std::max( limit_itr->sell_price, highest );
Copy link
Contributor

Choose a reason for hiding this comment

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

Is that still correct after HF_CORE_338?
The call will always be matched at the squeeze price, even if the limit order offers a better price. A call could have sufficient collateral to fill the limit order at its price, but insufficient collateral to fill at MSQP.

Important for understanding: check_for_blackswan is only called from check_call_orders.
check_call_orders currently always uses limit order price for filling call. That shouldn't be the case, though, if I understand BSIP-32 correctly.

Copy link
Contributor

Choose a reason for hiding this comment

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

Answer to previous remark:
After HF_625, check_call_orders is only ever called with the maker flag set to false. IOW after HF 338, check_call_orders is always taker, which means using the limit order price is correct, assuming that HF 338 and HF 625 happen simultaneously.

Copy link
Member Author

Choose a reason for hiding this comment

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

In short, this change is correct.

globally_settle_asset(mia, ~least_collateral );
if( maint_time > HARDFORK_CORE_338_TIME && ~least_collateral <= settle_price )
// global settle at feed price if possible
globally_settle_asset(mia, settle_price );
Copy link
Contributor

Choose a reason for hiding this comment

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

Still struggling with the legitimacy of this, but tending to think it's ok.

* 3 - both were filled
*/
template<typename OrderType>
int database::match( const limit_order_object& usd, const OrderType& core, const price& match_price )
int database::match( const limit_order_object& usd, const limit_order_object& core, const price& match_price )
{
assert( usd.sell_price.quote.asset_id == core.sell_price.base.asset_id );
Copy link
Contributor

Choose a reason for hiding this comment

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

Better turn these assert()s into FC_ASSERT()s as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually we need to carefully review all assert()s and FC_ASSERT()s as mentioned in #679 and #511 (comment).

For this one, if it would cause a chain halt, most probably would be caused by FBA buyback.

Copy link
Contributor

Choose a reason for hiding this comment

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

You replaced the template method with two specific implementations. The implementation for limit_order uses assert(), as did the template, but the implementation for call_order uses FC_ASSERT, which is different from the original. IMO we should stay consistent, either change both or none.

// the first param is a new order, thus taker
result |= fill_order( core, core_pays, core_receives, true, match_price, true ) << 1; // the second param is maker
result |= fill_limit_order( usd, usd_pays, usd_receives, false, match_price, false ); // the first param is taker
result |= fill_limit_order( core, core_pays, core_receives, true, match_price, true ) << 1; // the second param is maker
assert( result != 0 );
Copy link
Contributor

Choose a reason for hiding this comment

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

assert() -> FC_ASSERT()

@@ -643,8 +800,11 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan
bool filled_limit = false;
Copy link
Contributor

@pmconrad pmconrad Apr 8, 2018

Choose a reason for hiding this comment

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

Please add an FC_ASSERT to check_call_orders that ensures that for_new_limit_order is only true before HF 338 / 625 (see my remark on check_for_blackswan).

Copy link
Member Author

Choose a reason for hiding this comment

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

Similar as commented above, actually we need to carefully review all assert()s and FC_ASSERT()s as mentioned in #679 and #511 (comment), also be careful when adding new FC_ASSERT()s. Actually I want to get rid of all FC_ASSERT()s or catch them properly when processing post-transaction jobs in _apply_block().

For this one, if we add a FC_ASSERT() here then caused a chain halt, probably would be caused by clear_expired_feeds or FBA buyback.

Copy link
Contributor

Choose a reason for hiding this comment

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

After HF 388, check_call_orders / check_for_blackswan only operate correctly if the maker flag is false. Adding the suggested FC_ASSERT would enforce that this condition holds even if a future change mistakenly calls check_call_orders with the flag set to true.

General question (not rhetorical): what is worse, a chain halt or a chain operating with undefined and/or wrong behaviour?

Copy link
Member Author

Choose a reason for hiding this comment

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

IMHO at most times a chain halt is worse, but negative impact of undefined/wrong behavior is unbounded and sometimes is even worse. So I don't have a clear answer. I slightly tend to avoid chain halt.

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 the opposite, especially because wrong behaviour can go unnoticed for a long time.

We need more opinions. :-) @xeroc @oxarbitrage @ryanRfox

}
if( !abd || abd->is_prediction_market ) // nothing to do with PM's; check !abd just to be safe
continue;
db.modify( call_obj, [&]( call_order_object& call ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please capture only abd

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@pmconrad
Copy link
Contributor

pmconrad commented Apr 9, 2018

Please add/modify a test to cover this code path: https://sonarcloud.io/component?id=BitShares-develop%3Adevelop%3Alibraries%2Fchain%2Fdb_market.cpp&line=561

(Create a large limit order that is only partially filled by a margin call.)

@abitmore
Copy link
Member Author

abitmore commented Apr 9, 2018

@pmconrad done changes for this:

(Create a large limit order that is only partially filled by a margin call.)

//Update:
Ideally we need several test cases for different scenarios when placing a new limit order.

@abitmore
Copy link
Member Author

@pmconrad I've changed the assert()s to FC_ASSERT()s and added new FC_ASSERT() as requested. Please check again. WRT the PM black swan issue (#460), my opinion is we don't fix it this time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants