diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 6c00f89b25..c6be38b842 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -769,6 +769,7 @@ void database::process_bids( const asset_bitasset_data_object& bad ) void update_and_match_call_orders( database& db ) { // Update call_price + wlog( "Updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) ); asset_id_type current_asset; const asset_bitasset_data_object* abd = nullptr; // by_collateral index won't change after call_price updated, so it's safe to iterate @@ -796,6 +797,7 @@ void update_and_match_call_orders( database& db ) // 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 } + wlog( "Done updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) ); } void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index 9ee7749869..db97f8d02a 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -402,6 +402,8 @@ bool database::apply_order(const limit_order_object& new_order_object, bool allo // so a new order in the same direction with the call order won't trigger a black swan event. // 3. calling is one direction. if the new limit order is on the opposite direction, // no matter if matches with the call, it won't trigger a black swan event. + // (if a match at MSSP caused a black swan event, it means the call order is already undercollateralized, + // which should trigger a black swan event earlier.) // // Since it won't trigger a black swan, no need to check here. diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index cf2f1da86b..d5e7e520b4 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -209,6 +209,20 @@ bool database::check_for_blackswan( const asset_object& mia, bool enable_black_s const call_order_index& call_index = get_index_type(); const auto& call_price_index = call_index.indices().get(); + auto call_min = price::min( bitasset.options.short_backing_asset, mia.id ); + auto call_max = price::max( bitasset.options.short_backing_asset, mia.id ); + auto call_itr = call_price_index.lower_bound( call_min ); + auto call_end = call_price_index.upper_bound( call_max ); + + if( call_itr == call_end ) return false; // no call orders + + price highest = settle_price; + + auto maint_time = get_dynamic_global_properties().next_maintenance_time; + if( maint_time > HARDFORK_CORE_338_TIME ) + // due to #338, we won't check for black swan on incoming limit order, so need to check with MSSP here + highest = bitasset.current_feed.max_short_squeeze_price(); + const limit_order_index& limit_index = get_index_type(); const auto& limit_price_index = limit_index.indices().get(); @@ -217,41 +231,35 @@ bool database::check_for_blackswan( const asset_object& mia, bool enable_black_s // stop when limit orders are selling too little USD for too much CORE auto lowest_possible_bid = price::min( mia.id, bitasset.options.short_backing_asset ); - assert( highest_possible_bid.base.asset_id == lowest_possible_bid.base.asset_id ); + FC_ASSERT( highest_possible_bid.base.asset_id == lowest_possible_bid.base.asset_id ); // NOTE limit_price_index is sorted from greatest to least auto limit_itr = limit_price_index.lower_bound( highest_possible_bid ); auto limit_end = limit_price_index.upper_bound( lowest_possible_bid ); - auto call_min = price::min( bitasset.options.short_backing_asset, mia.id ); - auto call_max = price::max( bitasset.options.short_backing_asset, mia.id ); - auto call_itr = call_price_index.lower_bound( call_min ); - auto call_end = call_price_index.upper_bound( call_max ); - - if( call_itr == call_end ) return false; // no call orders - - price highest = settle_price; if( limit_itr != limit_end ) { - 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 ); } - // FIXME - // possible BUG: position with lowest call_price doesn't always have least collateral - // related to https://github.com/bitshares/bitshares-core/issues/343 auto least_collateral = call_itr->collateralization(); if( ~least_collateral >= highest ) { + wdump( (*call_itr) ); elog( "Black Swan detected: \n" " Least collateralized call: ${lc} ${~lc}\n" // " Highest Bid: ${hb} ${~hb}\n" - " Settle Price: ${sp} ${~sp}\n" - " Max: ${h} ${~h}\n", + " Settle Price: ${~sp} ${sp}\n" + " Max: ${~h} ${h}\n", ("lc",least_collateral.to_real())("~lc",(~least_collateral).to_real()) // ("hb",limit_itr->sell_price.to_real())("~hb",(~limit_itr->sell_price).to_real()) ("sp",settle_price.to_real())("~sp",(~settle_price).to_real()) ("h",highest.to_real())("~h",(~highest).to_real()) ); FC_ASSERT( enable_black_swan, "Black swan was detected during a margin update which is not allowed to trigger a blackswan" ); - globally_settle_asset(mia, ~least_collateral ); + if( maint_time > HARDFORK_CORE_338_TIME && ~least_collateral <= settle_price ) + // globol settle at feed price if possible + globally_settle_asset(mia, settle_price ); + else + globally_settle_asset(mia, ~least_collateral ); return true; } return false;