Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 39 additions & 32 deletions libraries/chain/asset_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,8 @@ void_result asset_update_evaluator::do_apply(const asset_update_operation& o)
{
const auto& bid_idx = d.get_index_type< collateral_bid_index >().indices().get<by_price>();
auto itr = bid_idx.lower_bound( o.asset_to_update );
while( itr != bid_idx.end() && itr->inv_swan_price.quote.asset_id == o.asset_to_update )
const auto end = bid_idx.upper_bound( o.asset_to_update );
while( itr != end )
{
const collateral_bid_object& bid = *itr;
++itr;
Expand Down Expand Up @@ -993,6 +994,7 @@ static bool update_bitasset_object_options(
const auto old_feed = bdo.current_feed;
// skip recalculating median feed if it is not needed
db.update_bitasset_current_feed( bdo, !should_update_feeds );
// Note: we don't try to revive the bitasset here if it was GSed // TODO probably we should do it

// We need to call check_call_orders if the settlement price changes after hardfork core-868-890
feed_actually_changed = ( after_hf_core_868_890 && !old_feed.margin_call_params_equal( bdo.current_feed ) );
Expand Down Expand Up @@ -1081,6 +1083,8 @@ void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_f
}
});
d.update_bitasset_current_feed( bitasset_to_update );
// Note: we don't try to revive the bitasset here if it was GSed // TODO probably we should do it

// Process margin calls, allow black swan, not for a new limit order
d.check_call_orders( *asset_to_update, true, false, &bitasset_to_update );

Expand Down Expand Up @@ -1233,6 +1237,7 @@ static extendable_operation_result pay_settle_from_gs_fund( database& d,
d.modify( mia_dyn, [&pays]( asset_dynamic_data_object& obj ){
obj.current_supply -= pays.amount;
});
// Note: we don't revive the asset here if current_supply become zero, but only do it on a new feed

extendable_operation_result result;

Expand Down Expand Up @@ -1420,41 +1425,43 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope
});
d.update_bitasset_current_feed( bad );

if( !old_feed.margin_call_params_equal(bad.current_feed) )
{
// Check whether need to revive the asset and proceed if need
if( bad.has_settlement() // has globally settled, implies head_block_time > HARDFORK_CORE_216_TIME
&& !bad.current_feed.settlement_price.is_null() ) // has a valid feed
if( old_feed.margin_call_params_equal(bad.current_feed) )
return void_result();

// Feed changed, check whether need to revive the asset and proceed if need
if( bad.has_settlement() // has globally settled, implies head_block_time > HARDFORK_CORE_216_TIME
&& !bad.current_feed.settlement_price.is_null() ) // has a valid feed
{
bool should_revive = false;
const auto& mia_dyn = base.dynamic_asset_data_id(d);
if( mia_dyn.current_supply == 0 ) // if current supply is zero, revive the asset
should_revive = true;
// if current supply is not zero, revive the asset when collateral ratio of settlement fund
// is greater than ( MCR if before HF core-2290, ICR if after)
else if( next_maint_time <= HARDFORK_CORE_1270_TIME )
{
bool should_revive = false;
const auto& mia_dyn = base.dynamic_asset_data_id(d);
if( mia_dyn.current_supply == 0 ) // if current supply is zero, revive the asset
should_revive = true;
else // if current supply is not zero, when collateral ratio of settlement fund is greater than MCR, revive the asset
{
if( next_maint_time <= HARDFORK_CORE_1270_TIME )
{
// before core-1270 hard fork, calculate call_price and compare to median feed
if( ~price::call_price( asset(mia_dyn.current_supply, o.asset_id),
asset(bad.settlement_fund, bad.options.short_backing_asset),
bad.current_feed.maintenance_collateral_ratio ) < bad.current_feed.settlement_price )
should_revive = true;
}
else
{
// after core-1270 hard fork, calculate collateralization and compare to maintenance_collateralization
if( price( asset( bad.settlement_fund, bad.options.short_backing_asset ),
asset( mia_dyn.current_supply, o.asset_id ) ) > bad.current_maintenance_collateralization )
should_revive = true;
}
}
if( should_revive )
d.revive_bitasset(base);
// before core-1270 hard fork, calculate call_price and compare to median feed
auto fund_call_price = ~price::call_price( asset(mia_dyn.current_supply, o.asset_id),
asset(bad.settlement_fund, bad.options.short_backing_asset),
bad.current_feed.maintenance_collateral_ratio );
should_revive = ( fund_call_price < bad.current_feed.settlement_price );
}
else
{
// after core-1270 hard fork, calculate collateralization and compare to maintenance_collateralization
price fund_collateralization( asset( bad.settlement_fund, bad.options.short_backing_asset ),
asset( mia_dyn.current_supply, o.asset_id ) );
should_revive = HARDFORK_CORE_2290_PASSED( next_maint_time ) ?
( fund_collateralization > bad.current_initial_collateralization )
: ( fund_collateralization > bad.current_maintenance_collateralization );
}
// Process margin calls, allow black swan, not for a new limit order
d.check_call_orders( base, true, false, bitasset_ptr );
if( should_revive )
d.revive_bitasset( base, bad );
}

// Process margin calls, allow black swan, not for a new limit order
d.check_call_orders( base, true, false, bitasset_ptr );

return void_result();
} FC_CAPTURE_AND_RETHROW((o)) }

Expand Down
57 changes: 33 additions & 24 deletions libraries/chain/db_maint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,35 +823,45 @@ void deprecate_annual_members( database& db )

void database::process_bids( const asset_bitasset_data_object& bad )
{
if( bad.is_prediction_market ) return;
if( bad.current_feed.settlement_price.is_null() ) return;
if( bad.is_prediction_market || bad.current_feed.settlement_price.is_null() )
return;

asset_id_type to_revive_id = (asset( 0, bad.options.short_backing_asset ) * bad.settlement_price).asset_id;
asset_id_type to_revive_id = bad.asset_id;
const asset_object& to_revive = to_revive_id( *this );
const asset_dynamic_data_object& bdd = to_revive.dynamic_data( *this );

if( 0 == bdd.current_supply ) // shortcut
{
_cancel_bids_and_revive_mpa( to_revive, bad );
return;
}

bool after_hf_core_2290 = HARDFORK_CORE_2290_PASSED( get_dynamic_global_properties().next_maintenance_time );

const auto& bid_idx = get_index_type< collateral_bid_index >().indices().get<by_price>();
const auto start = bid_idx.lower_bound( to_revive_id );
auto end = bid_idx.upper_bound( to_revive_id );

share_type covered = 0;
auto itr = start;
while( covered < bdd.current_supply && itr != bid_idx.end() && itr->inv_swan_price.quote.asset_id == to_revive_id )
auto revive_ratio = after_hf_core_2290 ? bad.current_feed.initial_collateral_ratio
: bad.current_feed.maintenance_collateral_ratio;
while( covered < bdd.current_supply && itr != end )
{
const collateral_bid_object& bid = *itr;
asset debt_in_bid = bid.inv_swan_price.quote;
if( debt_in_bid.amount > bdd.current_supply )
debt_in_bid.amount = bdd.current_supply;
asset total_collateral = debt_in_bid * bad.settlement_price;
total_collateral += bid.inv_swan_price.base;
price call_price = price::call_price( debt_in_bid, total_collateral,
bad.current_feed.maintenance_collateral_ratio );
price call_price = price::call_price( debt_in_bid, total_collateral, revive_ratio );
if( ~call_price >= bad.current_feed.settlement_price ) break;
covered += debt_in_bid.amount;
++itr;
}
if( covered < bdd.current_supply ) return;

const auto end = itr;
end = itr;
share_type to_cover = bdd.current_supply;
share_type remaining_fund = bad.settlement_fund;
itr = start;
Expand Down Expand Up @@ -943,29 +953,28 @@ void database::process_bitassets()
uint32_t head_epoch_seconds = head_time.sec_since_epoch();
bool after_hf_core_518 = ( head_time >= HARDFORK_CORE_518_TIME ); // clear expired feeds

const auto update_bitasset = [this,head_time,head_epoch_seconds,after_hf_core_518]( asset_bitasset_data_object &o )
const auto& update_bitasset = [this,&head_time,head_epoch_seconds,after_hf_core_518]
( asset_bitasset_data_object &o )
{
o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero

// clear expired feeds
if( after_hf_core_518 )
// clear expired feeds if smartcoin (witness_fed or committee_fed) && check overflow
if( after_hf_core_518 && o.options.feed_lifetime_sec < head_epoch_seconds
&& ( 0 != ( o.asset_id(*this).options.flags & ( witness_fed_asset | committee_fed_asset ) ) ) )
{
const auto &asset = get( o.asset_id );
auto flags = asset.options.flags;
if ( ( 0 != ( flags & ( witness_fed_asset | committee_fed_asset ) ) ) &&
o.options.feed_lifetime_sec < head_epoch_seconds ) // if smartcoin && check overflow
fc::time_point_sec calculated = head_time - o.options.feed_lifetime_sec;
auto itr = o.feeds.rbegin();
auto end = o.feeds.rend();
while( itr != end ) // loop feeds
{
fc::time_point_sec calculated = head_time - o.options.feed_lifetime_sec;
auto itr = o.feeds.rbegin();
auto end = o.feeds.rend();
while( itr != end ) // loop feeds
{
auto feed_time = itr->second.first;
std::advance( itr, 1 );
if( feed_time < calculated )
o.feeds.erase( itr.base() ); // delete expired feed
}
auto feed_time = itr->second.first;
std::advance( itr, 1 );
if( feed_time < calculated )
o.feeds.erase( itr.base() ); // delete expired feed
}
// Note: we don't update current_feed here, and the update_expired_feeds() call is a bit too late,
// so theoretically there could be an inconsistency between active feeds and current_feed.
// And note that the next step "process_bids()" is based on current_feed.
}
};

Expand Down
21 changes: 12 additions & 9 deletions libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,22 +407,23 @@ void database::individually_settle( const asset_bitasset_data_object& bitasset,

}

void database::revive_bitasset( const asset_object& bitasset )
void database::revive_bitasset( const asset_object& bitasset, const asset_bitasset_data_object& bad )
{ try {
FC_ASSERT( bitasset.is_market_issued() );
const asset_bitasset_data_object& bad = bitasset.bitasset_data(*this);
FC_ASSERT( bitasset.id == bad.asset_id );
FC_ASSERT( bad.has_settlement() );
const asset_dynamic_data_object& bdd = bitasset.dynamic_asset_data_id(*this);
FC_ASSERT( !bad.is_prediction_market );
FC_ASSERT( !bad.current_feed.settlement_price.is_null() );

const asset_dynamic_data_object& bdd = bitasset.dynamic_asset_data_id(*this);
if( bdd.current_supply > 0 )
{
// Create + execute a "bid" with 0 additional collateral
const collateral_bid_object& pseudo_bid = create<collateral_bid_object>([&](collateral_bid_object& bid) {
const collateral_bid_object& pseudo_bid = create<collateral_bid_object>(
[&bitasset,&bad,&bdd](collateral_bid_object& bid) {
bid.bidder = bitasset.issuer;
bid.inv_swan_price = asset(0, bad.options.short_backing_asset)
/ asset(bdd.current_supply, bitasset.id);
/ asset(bdd.current_supply, bad.asset_id);
});
execute_bid( pseudo_bid, bdd.current_supply, bad.settlement_fund, bad.current_feed );
} else
Expand All @@ -440,15 +441,16 @@ void database::_cancel_bids_and_revive_mpa( const asset_object& bitasset, const
// cancel remaining bids
const auto& bid_idx = get_index_type< collateral_bid_index >().indices().get<by_price>();
auto itr = bid_idx.lower_bound( bad.asset_id );
while( itr != bid_idx.end() && itr->inv_swan_price.quote.asset_id == bad.asset_id )
const auto end = bid_idx.upper_bound( bad.asset_id );
while( itr != end )
{
const collateral_bid_object& bid = *itr;
++itr;
cancel_bid( bid );
}

// revive
modify( bad, [&]( asset_bitasset_data_object& obj ){
modify( bad, []( asset_bitasset_data_object& obj ){
obj.settlement_price = price();
obj.settlement_fund = 0;
});
Expand All @@ -472,7 +474,8 @@ void database::cancel_bid(const collateral_bid_object& bid, bool create_virtual_
void database::execute_bid( const collateral_bid_object& bid, share_type debt_covered,
share_type collateral_from_fund, const price_feed& current_feed )
{
const call_order_object& call_obj = create<call_order_object>( [&](call_order_object& call ){
const call_order_object& call_obj = create<call_order_object>(
[&bid, &debt_covered, &collateral_from_fund, &current_feed, this](call_order_object& call ){
call.borrower = bid.bidder;
call.collateral = bid.inv_swan_price.base.amount + collateral_from_fund;
call.debt = debt_covered;
Expand All @@ -489,7 +492,7 @@ void database::execute_bid( const collateral_bid_object& bid, share_type debt_co

// Note: CORE asset in collateral_bid_object is not counted in account_stats.total_core_in_orders
if( bid.inv_swan_price.base.asset_id == asset_id_type() )
modify( get_account_stats_by_owner(bid.bidder), [&](account_statistics_object& stats) {
modify( get_account_stats_by_owner(bid.bidder), [&call_obj](account_statistics_object& stats) {
stats.total_core_in_orders += call_obj.collateral;
});

Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/db_update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ void database::update_expired_feeds()
auto old_median_feed = b.current_feed;
const asset_object& asset_obj = b.asset_id( *this );
update_bitasset_current_feed( b );
// Note: we don't try to revive the bitasset here if it was GSed // TODO probably we should do it

if( !b.current_feed.settlement_price.is_null()
&& !b.current_feed.margin_call_params_equal( old_median_feed ) )
{
Expand Down
6 changes: 6 additions & 0 deletions libraries/chain/hardfork.d/CORE_2290.hf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// bitshares-core issue #2290 Revival of globally-settled assets should depend on ICR but not MCR
#ifndef HARDFORK_CORE_2290_TIME
// Jan 1 2030, midnight; this is a dummy date until a hardfork date is scheduled
#define HARDFORK_CORE_2290_TIME (fc::time_point_sec( 1893456000 ))
#define HARDFORK_CORE_2290_PASSED(now) (now > HARDFORK_CORE_2290_TIME)
#endif
2 changes: 1 addition & 1 deletion libraries/chain/include/graphene/chain/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ namespace graphene { namespace chain {
void cancel_limit_order( const limit_order_object& order,
bool create_virtual_op = true,
bool skip_cancel_fee = false );
void revive_bitasset( const asset_object& bitasset );
void revive_bitasset( const asset_object& bitasset, const asset_bitasset_data_object& bad );
void cancel_bid(const collateral_bid_object& bid, bool create_virtual_op = true);
void execute_bid( const collateral_bid_object& bid, share_type debt_covered,
share_type collateral_from_fund, const price_feed& current_feed );
Expand Down
Loading