From cb78fc501fcc42f8a4d80dc31f9472e3b3a9f63a Mon Sep 17 00:00:00 2001 From: abitmore Date: Mon, 21 May 2018 18:36:23 -0400 Subject: [PATCH 01/13] update_bitasset: check current_feed changes #935 --- libraries/chain/asset_evaluator.cpp | 21 +++++++++++++++++++-- libraries/chain/hardfork.d/CORE_935.hf | 4 ++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_935.hf diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 61c2d0f70c..c4b50d2661 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -463,11 +463,28 @@ static bool update_bitasset_object_options( if( should_update_feeds ) { - const auto old_feed_price = bdo.current_feed.settlement_price; + const auto old_feed = bdo.current_feed; bdo.update_median_feeds( db.head_block_time() ); + // TODO review and refactor / cleanup after hard fork: + // 1. if hf_core_868_890 and core-935 occurred at same time + // 2. if wlog did not actually get called + + // We need to call check_call_orders if the price feed changes after hardfork core-935 + if( next_maint_time > HARDFORK_CORE_935_TIME ) + return ( !( old_feed == bdo.current_feed ) ); + // We need to call check_call_orders if the settlement price changes after hardfork core-868-890 - return after_hf_core_868_890 && old_feed_price != bdo.current_feed.settlement_price; + if( after_hf_core_868_890 ) + { + if( old_feed.settlement_price != bdo.current_feed.settlement_price ) + return true; + else + { + if( !( old_feed == bdo.current_feed ) ) + wlog( "Settlement price did not change but current_feed changed at block ${b}", ("b",db.head_block_num()) ); + } + } } return false; diff --git a/libraries/chain/hardfork.d/CORE_935.hf b/libraries/chain/hardfork.d/CORE_935.hf new file mode 100644 index 0000000000..8cce68a098 --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_935.hf @@ -0,0 +1,4 @@ +// bitshares-core issue #935 Call check_call_orders not only when settlement_price changed +#ifndef HARDFORK_CORE_935_TIME +#define HARDFORK_CORE_935_TIME (fc::time_point_sec( 1537625300 )) +#endif From 0f0b55d1d0c05b0ea3c8e2f67c4a0ce28f8f0752 Mon Sep 17 00:00:00 2001 From: abitmore Date: Mon, 21 May 2018 21:05:07 -0400 Subject: [PATCH 02/13] db_maint: call check_call_orders at hf time #935 --- libraries/chain/db_maint.cpp | 66 +++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 244c923608..8dfa669c3e 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -856,7 +856,7 @@ void database::process_bitassets() */ // TODO: for better performance, this function can be removed if it actually updated nothing at hf time. // * Also need to update related test cases -// * NOTE: perhaps the removal can't be applied to testnet +// * NOTE: the removal can't be applied to testnet void process_hf_868_890( database& db, bool skip_check_call_orders ) { auto head_time = db.head_block_time(); @@ -875,8 +875,8 @@ void process_hf_868_890( database& db, bool skip_check_call_orders ) // for each feed const asset_bitasset_data_object& bitasset_data = current_asset.bitasset_data(db); - // NOTE: We'll only need old_price if HF343 hasn't rolled out yet - auto old_price = bitasset_data.current_feed.settlement_price; + // NOTE: We'll only need old_feed if HF343 hasn't rolled out yet + auto old_feed = bitasset_data.current_feed; bool feeds_changed = false; // did any feed change auto itr = bitasset_data.feeds.begin(); while( itr != bitasset_data.feeds.end() ) @@ -920,13 +920,18 @@ void process_hf_868_890( database& db, bool skip_check_call_orders ) obj.update_median_feeds( head_time ); }); - bool median_changed = ( old_price != bitasset_data.current_feed.settlement_price ); - if( median_changed ) + bool median_changed = ( old_feed.settlement_price != bitasset_data.current_feed.settlement_price ); + bool median_feed_changed = ( !( old_feed == bitasset_data.current_feed ) ); + if( median_feed_changed ) { wlog( "Median feed for asset ${asset_sym} (${asset_id}) changed during hardfork core-868-890", ("asset_sym", current_asset.symbol)("asset_id", current_asset.id) ); } + // Note: due to bitshares-core issue #935, this check below (using median_changed) is incorrect. + // However, `skip_check_call_orders` will likely be true in both testnet and mainnet, + // so effectively the incorrect code won't make a difference. + // TODO cleanup after hard fork if( !skip_check_call_orders && median_changed ) // check_call_orders should be called { db.check_call_orders( current_asset ); @@ -934,6 +939,52 @@ void process_hf_868_890( database& db, bool skip_check_call_orders ) } // for each market issued asset } +/****** + * @brief one-time data process for hard fork core-935 + * + * Prior to hardfork 935, `check_call_orders` may be unintendedly skipped when + * median price feed has changed. This method will run at the hardfork time, and + * call `check_call_orders` for all markets. + * https://github.com/bitshares/bitshares-core/issues/935 + * + * @param db the database + */ +// TODO: for better performance, this function can be removed if it actually updated nothing at hf time. +// * Also need to update related test cases +// * NOTE: perhaps the removal can't be applied to testnet +void process_hf_935( database& db ) +{ + bool changed_something = false; + const asset_bitasset_data_object* bitasset = nullptr; + bool settled_before_check_call; + bool settled_after_check_call; + // for each market issued asset + const auto& asset_idx = db.get_index_type().indices().get(); + for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_idx.end(); ++asset_itr ) + { + const auto& current_asset = *asset_itr; + + if( !changed_something ) + { + bitasset = ¤t_asset.bitasset_data( db ); + settled_before_check_call = bitasset->has_settlement(); // whether already force settled + } + + bool called_some = db.check_call_orders( current_asset ); + + if( !changed_something ) + { + settled_after_check_call = bitasset->has_settlement(); // whether already force settled + + if( settled_before_check_call != settled_after_check_call || called_some ) + { + changed_something = true; + wlog( "process_hf_935 changed something" ); + } + } + } +} + void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) { const auto& gpo = get_global_properties(); @@ -1094,6 +1145,11 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g if( (dgpo.next_maintenance_time <= HARDFORK_CORE_868_890_TIME) && (next_maintenance_time > HARDFORK_CORE_868_890_TIME) ) process_hf_868_890( *this, to_update_and_match_call_orders ); + // Explicitly call check_call_orders of all markets + if( (dgpo.next_maintenance_time <= HARDFORK_CORE_935_TIME) && (next_maintenance_time > HARDFORK_CORE_935_TIME) + && !to_update_and_match_call_orders ) + process_hf_935( *this ); + modify(dgpo, [next_maintenance_time](dynamic_global_property_object& d) { d.next_maintenance_time = next_maintenance_time; d.accounts_registered_this_interval = 0; From f87aaa4b9d83854e69e95d46c5c5b932fe5db96e Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 23 May 2018 14:31:12 -0400 Subject: [PATCH 03/13] Tests check_call_orders when only MCR changed #935 --- tests/common/database_fixture.cpp | 11 +- tests/common/database_fixture.hpp | 3 +- tests/tests/bitasset_tests.cpp | 187 ++++++++++++++++++++++++++++-- 3 files changed, 187 insertions(+), 14 deletions(-) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 4cf8b2cbc3..4567a69a19 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -351,20 +351,25 @@ void database_fixture::generate_blocks( uint32_t block_count ) generate_block(); } -void database_fixture::generate_blocks(fc::time_point_sec timestamp, bool miss_intermediate_blocks, uint32_t skip) +uint32_t database_fixture::generate_blocks(fc::time_point_sec timestamp, bool miss_intermediate_blocks, uint32_t skip) { if( miss_intermediate_blocks ) { generate_block(skip); auto slots_to_miss = db.get_slot_at_time(timestamp); if( slots_to_miss <= 1 ) - return; + return 1; --slots_to_miss; generate_block(skip, init_account_priv_key, slots_to_miss); - return; + return 2; } + uint32_t blocks = 0; while( db.head_block_time() < timestamp ) + { generate_block(skip); + ++blocks; + } + return blocks; } account_create_operation database_fixture::make_account( diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 1c7ec36e3a..a91f164f62 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -184,8 +184,9 @@ struct database_fixture { /** * @brief Generates blocks until the head block time matches or exceeds timestamp * @param timestamp target time to generate blocks until + * @return number of blocks generated */ - void generate_blocks(fc::time_point_sec timestamp, bool miss_intermediate_blocks = true, uint32_t skip = ~0); + uint32_t generate_blocks(fc::time_point_sec timestamp, bool miss_intermediate_blocks = true, uint32_t skip = ~0); account_create_operation make_account( const std::string& name = "nathan", diff --git a/tests/tests/bitasset_tests.cpp b/tests/tests/bitasset_tests.cpp index d89c775665..6f9e5beedd 100644 --- a/tests/tests/bitasset_tests.cpp +++ b/tests/tests/bitasset_tests.cpp @@ -434,10 +434,8 @@ BOOST_AUTO_TEST_CASE( hf_890_test ) if( i == 1 ) // go beyond hard fork { - generate_blocks(HARDFORK_CORE_868_890_TIME - mi, true, skip); - blocks += 2; - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); - blocks += 2; + blocks += generate_blocks(HARDFORK_CORE_868_890_TIME - mi, true, skip); + blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); } set_expiration( db, trx ); @@ -486,8 +484,7 @@ BOOST_AUTO_TEST_CASE( hf_890_test ) // settlement price = 100 USD / 10 CORE, mssp = 100/11 USD/CORE // let the feed expire - generate_blocks( db.head_block_time() + 1200, true, skip ); - blocks += 2; + blocks += generate_blocks( db.head_block_time() + 1200, true, skip ); set_expiration( db, trx ); // check: median feed should be null @@ -519,10 +516,8 @@ BOOST_AUTO_TEST_CASE( hf_890_test ) BOOST_CHECK( db.find( sell_id ) ); // go beyond hard fork - generate_blocks(HARDFORK_CORE_868_890_TIME - mi, true, skip); - blocks += 2; - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); - blocks += 2; + blocks += generate_blocks(HARDFORK_CORE_868_890_TIME - mi, true, skip); + blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); } // after hard fork, median feed should become valid, and the limit order should be filled @@ -542,6 +537,178 @@ BOOST_AUTO_TEST_CASE( hf_890_test ) } } +/********* + * @brief Call check_call_orders after current_feed changed but not only settlement_price changed. + */ +BOOST_AUTO_TEST_CASE( hf_935_test ) +{ try { + uint32_t skip = database::skip_witness_signature + | database::skip_transaction_signatures + | database::skip_transaction_dupe_check + | database::skip_block_size_check + | database::skip_tapos_check + | database::skip_authority_check + | database::skip_merkle_check + ; + generate_blocks( HARDFORK_615_TIME, true, skip ); // get around Graphene issue #615 feed expiration bug + generate_blocks( db.get_dynamic_global_properties().next_maintenance_time, true, skip ); + generate_block( skip ); + + for( int i = 0; i < 3; ++i ) + { + idump( (i) ); + int blocks = 0; + auto mi = db.get_global_properties().parameters.maintenance_interval; + + if( i == 1 ) // go beyond hard fork 890 + { + generate_blocks( HARDFORK_CORE_868_890_TIME - mi, true, skip ); + generate_blocks( db.get_dynamic_global_properties().next_maintenance_time, true, skip ); + } + else if( i == 2 ) // go beyond hard fork 935 + { + generate_blocks( HARDFORK_CORE_935_TIME - mi, true, skip ); + generate_blocks( db.get_dynamic_global_properties().next_maintenance_time, true, skip ); + } + set_expiration( db, trx ); + + ACTORS( (seller)(borrower)(feedproducer)(feedproducer2)(feedproducer3) ); + + int64_t init_balance( 1000000 ); + + transfer( committee_account, borrower_id, asset(init_balance) ); + + const auto& bitusd = create_bitasset( "USDBIT", feedproducer_id ); + asset_id_type usd_id = bitusd.id; + + { + // change feed lifetime (2x maintenance interval) + const asset_object& asset_to_update = usd_id(db); + asset_update_bitasset_operation ba_op; + ba_op.asset_to_update = usd_id; + ba_op.issuer = asset_to_update.issuer; + ba_op.new_options = asset_to_update.bitasset_data(db).options; + ba_op.new_options.feed_lifetime_sec = 300; + trx.operations.push_back(ba_op); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + // set feed producers + flat_set producers; + producers.insert( feedproducer_id ); + producers.insert( feedproducer2_id ); + producers.insert( feedproducer3_id ); + update_feed_producers( usd_id(db), producers ); + + // prepare feed data + price_feed current_feed; + current_feed.maintenance_collateral_ratio = 3500; + current_feed.maximum_short_squeeze_ratio = 1100; + + // set 2 price feeds with 350% MCR + current_feed.settlement_price = asset(100, usd_id) / asset(5); + publish_feed( usd_id, feedproducer_id, current_feed ); + publish_feed( usd_id, feedproducer2_id, current_feed ); + + // check median, MCR should be 350% + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + + // generate some blocks, let the feeds expire + blocks += generate_blocks( db.head_block_time() + 360, true, skip ); + set_expiration( db, trx ); + + // check median, should be null + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price.is_null() ); + + // publish a new feed with 175% MCR, new median MCR would be 175% + current_feed.maintenance_collateral_ratio = 1750; + publish_feed( usd_id, feedproducer3_id, current_feed ); + + // check median, MCR should be 175% + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); + + // Place some collateralized orders + // start out with 300% collateral, call price is 15/175 CORE/USD = 60/700 + borrow( borrower_id, asset(100, usd_id), asset(15) ); + + transfer( borrower_id, seller_id, asset(100, usd_id) ); + + // place a sell order, it won't be matched with the call order now. + // when median MCR changed to 350%, the call order with 300% collateral will be in margin call territory, + // then this limit order should be filled + limit_order_id_type sell_id = create_sell_order( seller_id, asset(20, usd_id), asset(1) )->id; + + { + // change feed lifetime to longer, let all 3 feeds be valid + const asset_object& asset_to_update = usd_id(db); + asset_update_bitasset_operation ba_op; + ba_op.asset_to_update = usd_id; + ba_op.issuer = asset_to_update.issuer; + ba_op.new_options = asset_to_update.bitasset_data(db).options; + ba_op.new_options.feed_lifetime_sec = HARDFORK_CORE_935_TIME.sec_since_epoch() + - db.head_block_time().sec_since_epoch() + + mi * 3; + trx.operations.push_back(ba_op); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + // check + if( i == 0 ) // before hard fork 890 + { + // median feed won't change (issue 890) + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); + // limit order is still there + BOOST_CHECK( db.find( sell_id ) ); + + // go beyond hard fork 890 + blocks += generate_blocks(HARDFORK_CORE_868_890_TIME - mi, true, skip); + blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); + } + + // after hard fork 890, if it's before hard fork 935 + if( db.get_dynamic_global_properties().next_maintenance_time <= HARDFORK_CORE_935_TIME ) + { + // median should have changed + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + // but the limit order is still there, because `check_call_order` was incorrectly skipped + BOOST_CHECK( db.find( sell_id ) ); + + // go beyond hard fork 935 + blocks += generate_blocks(HARDFORK_CORE_935_TIME - mi, true, skip); + blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); + } + + // after hard fork 935, the limit order should be filled + { + // median MCR should be 350% + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + // the limit order is still there, because `check_call_order` is skipped + BOOST_CHECK( !db.find( sell_id ) ); + if( db.find( sell_id ) ) + { + idump( (sell_id(db)) ); + } + } + + + // undo above tx's and reset + generate_block( skip ); + ++blocks; + while( blocks > 0 ) + { + db.pop_block(); + --blocks; + } + } +} FC_LOG_AND_RETHROW() } + /***** * @brief make sure feeds work correctly after changing from non-witness-fed to witness-fed before the 868 fork * NOTE: This test case is a different issue than what is currently being worked on, and fails. Hopefully it From 5e28975cc7abe7459a61af839e1ba9fa601529e1 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 23 May 2018 19:01:35 -0400 Subject: [PATCH 04/13] Defer MCR update to next maintenance interval #935 --- libraries/chain/asset_evaluator.cpp | 13 +- libraries/chain/asset_object.cpp | 34 +++-- libraries/chain/db_maint.cpp | 140 +++++++++--------- libraries/chain/db_update.cpp | 12 +- .../include/graphene/chain/asset_object.hpp | 38 ++++- .../chain/include/graphene/chain/config.hpp | 2 +- 6 files changed, 141 insertions(+), 98 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index c4b50d2661..bc196f3ea9 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -413,7 +413,7 @@ static bool update_bitasset_object_options( const asset_update_bitasset_operation& op, database& db, asset_bitasset_data_object& bdo, const asset_object& asset_to_update ) { - const fc::time_point_sec& next_maint_time = db.get_dynamic_global_properties().next_maintenance_time; + fc::time_point_sec next_maint_time = db.get_dynamic_global_properties().next_maintenance_time; bool after_hf_core_868_890 = ( next_maint_time > HARDFORK_CORE_868_890_TIME ); // If the minimum number of feeds to calculate a median has changed, we need to recalculate the median @@ -464,7 +464,7 @@ static bool update_bitasset_object_options( if( should_update_feeds ) { const auto old_feed = bdo.current_feed; - bdo.update_median_feeds( db.head_block_time() ); + bdo.update_median_feeds( db.head_block_time(), next_maint_time ); // TODO review and refactor / cleanup after hard fork: // 1. if hf_core_868_890 and core-935 occurred at same time @@ -534,7 +534,8 @@ void_result asset_update_feed_producers_evaluator::do_evaluate(const asset_updat void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_feed_producers_evaluator::operation_type& o) { try { - db().modify(*bitasset_to_update, [&](asset_bitasset_data_object& a) { + database& d = db(); + d.modify(*bitasset_to_update, [&d, &o](asset_bitasset_data_object& a) { //This is tricky because I have a set of publishers coming in, but a map of publisher to feed is stored. //I need to update the map such that the keys match the new publishers, but not munge the old price feeds from //publishers who are being kept. @@ -550,9 +551,9 @@ void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_f for( auto itr = o.new_feed_producers.begin(); itr != o.new_feed_producers.end(); ++itr ) if( !a.feeds.count(*itr) ) a.feeds[*itr]; - a.update_median_feeds(db().head_block_time()); + a.update_median_feeds( d.head_block_time(), d.get_dynamic_global_properties().next_maintenance_time ); }); - db().check_call_orders( o.asset_to_update(db()) ); + d.check_call_orders( o.asset_to_update(d) ); return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } @@ -727,7 +728,7 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope // Store medians for this asset d.modify(bad , [&o,&d](asset_bitasset_data_object& a) { a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed); - a.update_median_feeds(d.head_block_time()); + a.update_median_feeds( d.head_block_time(), d.get_dynamic_global_properties().next_maintenance_time ); }); if( !(old_feed == bad.current_feed) ) diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 4c1648599f..45481079d0 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -23,6 +23,7 @@ */ #include #include +#include #include @@ -43,15 +44,8 @@ share_type asset_bitasset_data_object::max_force_settlement_volume(share_type cu return volume.to_uint64(); } -/****** - * @brief calculate the median feed - * - * This calculates the median feed. It sets the current_feed_publication_time - * and current_feed member variables - * - * @param current_time the time to use in the calculations - */ -void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point_sec current_time) +void graphene::chain::asset_bitasset_data_object::update_median_feeds( time_point_sec current_time, + time_point_sec next_maintenance_time ) { current_feed_publication_time = current_time; vector> current_feeds; @@ -71,12 +65,14 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point { //... don't calculate a median, and set a null feed current_feed_publication_time = current_time; - current_feed = price_feed(); + price_feed null_feed; + update_current_feed( null_feed, next_maintenance_time ); return; } if( current_feeds.size() == 1 ) { - current_feed = std::move(current_feeds.front()); + price_feed only_feed = std::move( current_feeds.front() ); + update_current_feed( only_feed, next_maintenance_time ); return; } @@ -94,7 +90,21 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point #undef CALCULATE_MEDIAN_VALUE // *** End Median Calculations *** - current_feed = median_feed; + update_current_feed( median_feed, next_maintenance_time ); +} + +void graphene::chain::asset_bitasset_data_object::update_current_feed( price_feed& new_feed, + time_point_sec next_maintenance_time ) +{ + if( next_maintenance_time > HARDFORK_CORE_935_TIME ) + { + if( current_feed.maintenance_collateral_ratio == new_feed.maintenance_collateral_ratio ) + pending_maintenance_collateral_ratio.reset(); + else + pending_maintenance_collateral_ratio = new_feed.maintenance_collateral_ratio; + new_feed.maintenance_collateral_ratio = current_feed.maintenance_collateral_ratio; + } + current_feed = std::move( new_feed ); } diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 8dfa669c3e..f5f9541545 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -766,38 +766,79 @@ void database::process_bids( const asset_bitasset_data_object& bad ) _cancel_bids_and_revive_mpa( to_revive, bad ); } -void update_and_match_call_orders( database& db ) +/** + * @brief Update and match call orders + * @param db The database + * @param bitasset set to `nullptr` to update all call orders, otherwise only update call orders of this asset + */ +void update_and_match_call_orders( database& db, const asset_bitasset_data_object* bitasset = nullptr ) { + if( !bitasset ) + wlog( "Updating all call orders for hardfork core-343/935 at block ${n}", ("n",db.head_block_num()) ); + // 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; + asset_id_type current_asset = bitasset ? bitasset->asset_id : asset_id_type(); + const asset_bitasset_data_object* abd = bitasset; + // by_collateral index won't change after call_price updated, so it's safe to iterate - for( const auto& call_obj : db.get_index_type().indices().get() ) + const auto& call_idx = db.get_index_type().indices().get(); + auto citr = abd ? call_idx.lower_bound( price::min( abd->options.short_backing_asset, current_asset ) ) + : call_idx.begin(); + auto cend = abd ? call_idx.upper_bound( price::max( abd->options.short_backing_asset, current_asset ) ) + : call_idx.end(); + while( citr != cend ) { - if( current_asset != call_obj.debt_type() ) // debt type won't be asset_id_type(), abd will always get initialized - { + const call_order_object& call_obj = *citr; + ++citr; + if( !bitasset && current_asset != call_obj.debt_type() ) // only do this when updating all call orders + { // debt type won't be asset_id_type(), so abd will always get initialized current_asset = call_obj.debt_type(); abd = ¤t_asset(db).bitasset_data(db); } - if( !abd || abd->is_prediction_market ) // nothing to do with PM's; check !abd just to be safe - continue; + // note: to be consistent with `call_order_update_evaluator::do_apply()`, process prediction markets as well db.modify( call_obj, [abd]( call_order_object& call ) { call.call_price = price::call_price( call.get_debt(), call.get_collateral(), abd->current_feed.maintenance_collateral_ratio ); }); } + // Match call orders - const auto& asset_idx = db.get_index_type().indices().get(); - auto itr = asset_idx.lower_bound( true /** market issued */ ); - while( itr != asset_idx.end() ) + if( bitasset ) + db.check_call_orders( current_asset(db), true, false ); // allow black swan, and call orders are taker + else { - 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 + const auto& asset_idx = db.get_index_type().indices().get(); + auto itr = asset_idx.lower_bound( true /** market issued */ ); + while( itr != asset_idx.end() ) + { + 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 + } + wlog( "Done updating all call orders for hardfork core-343/935 at block ${n}", ("n",db.head_block_num()) ); + } +} + +/** + * @brief Process pending_maintenance_collateral_ratio data for all MPA's + * @param db The database + */ +void process_pending_mcr( database& db ) +{ + const auto& bitasset_idx = db.get_index_type().indices().get(); + auto ba_itr = bitasset_idx.upper_bound( optional() ); // has something pending + while( ba_itr != bitasset_idx.end() ) + { + const asset_bitasset_data_object& abd = *ba_itr; + ++ba_itr; + db.modify( abd, []( asset_bitasset_data_object& abdo ) + { + abdo.current_feed.maintenance_collateral_ratio = *abdo.pending_maintenance_collateral_ratio; + abdo.pending_maintenance_collateral_ratio.reset(); + }); + update_and_match_call_orders( db, &abd ); } - wlog( "Done updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) ); } void database::process_bitassets() @@ -853,11 +894,12 @@ void database::process_bitassets() * * @param db the database * @param skip_check_call_orders true if check_call_orders() should not be called + * @param next_maintenance_time the next maintenance time */ // TODO: for better performance, this function can be removed if it actually updated nothing at hf time. // * Also need to update related test cases // * NOTE: the removal can't be applied to testnet -void process_hf_868_890( database& db, bool skip_check_call_orders ) +void process_hf_868_890( database& db, bool skip_check_call_orders, time_point_sec next_maintenance_time ) { auto head_time = db.head_block_time(); // for each market issued asset @@ -916,8 +958,8 @@ void process_hf_868_890( database& db, bool skip_check_call_orders ) } // always update the median feed due to https://github.com/bitshares/bitshares-core/issues/890 - db.modify( bitasset_data, [&head_time]( asset_bitasset_data_object &obj ) { - obj.update_median_feeds( head_time ); + db.modify( bitasset_data, [head_time,next_maintenance_time]( asset_bitasset_data_object &obj ) { + obj.update_median_feeds( head_time, next_maintenance_time ); }); bool median_changed = ( old_feed.settlement_price != bitasset_data.current_feed.settlement_price ); @@ -939,52 +981,6 @@ void process_hf_868_890( database& db, bool skip_check_call_orders ) } // for each market issued asset } -/****** - * @brief one-time data process for hard fork core-935 - * - * Prior to hardfork 935, `check_call_orders` may be unintendedly skipped when - * median price feed has changed. This method will run at the hardfork time, and - * call `check_call_orders` for all markets. - * https://github.com/bitshares/bitshares-core/issues/935 - * - * @param db the database - */ -// TODO: for better performance, this function can be removed if it actually updated nothing at hf time. -// * Also need to update related test cases -// * NOTE: perhaps the removal can't be applied to testnet -void process_hf_935( database& db ) -{ - bool changed_something = false; - const asset_bitasset_data_object* bitasset = nullptr; - bool settled_before_check_call; - bool settled_after_check_call; - // for each market issued asset - const auto& asset_idx = db.get_index_type().indices().get(); - for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_idx.end(); ++asset_itr ) - { - const auto& current_asset = *asset_itr; - - if( !changed_something ) - { - bitasset = ¤t_asset.bitasset_data( db ); - settled_before_check_call = bitasset->has_settlement(); // whether already force settled - } - - bool called_some = db.check_call_orders( current_asset ); - - if( !changed_something ) - { - settled_after_check_call = bitasset->has_settlement(); // whether already force settled - - if( settled_before_check_call != settled_after_check_call || called_some ) - { - changed_something = true; - wlog( "process_hf_935 changed something" ); - } - } - } -} - void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) { const auto& gpo = get_global_properties(); @@ -1138,17 +1134,17 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // To reset call_price of all call orders, then match by new rule bool to_update_and_match_call_orders = false; - if( (dgpo.next_maintenance_time <= HARDFORK_CORE_343_TIME) && (next_maintenance_time > HARDFORK_CORE_343_TIME) ) + if( ( dgpo.next_maintenance_time <= HARDFORK_CORE_343_TIME && next_maintenance_time > HARDFORK_CORE_343_TIME ) + || ( dgpo.next_maintenance_time <= HARDFORK_CORE_935_TIME && next_maintenance_time > HARDFORK_CORE_935_TIME ) ) to_update_and_match_call_orders = true; // Process inconsistent price feeds if( (dgpo.next_maintenance_time <= HARDFORK_CORE_868_890_TIME) && (next_maintenance_time > HARDFORK_CORE_868_890_TIME) ) - process_hf_868_890( *this, to_update_and_match_call_orders ); + process_hf_868_890( *this, to_update_and_match_call_orders, next_maintenance_time ); - // Explicitly call check_call_orders of all markets - if( (dgpo.next_maintenance_time <= HARDFORK_CORE_935_TIME) && (next_maintenance_time > HARDFORK_CORE_935_TIME) - && !to_update_and_match_call_orders ) - process_hf_935( *this ); + // Process pending_maitenance_collateral_ratio data for all MPA's + if( dgpo.next_maintenance_time > HARDFORK_CORE_935_TIME ) + process_pending_mcr( *this ); modify(dgpo, [next_maintenance_time](dynamic_global_property_object& d) { d.next_maintenance_time = next_maintenance_time; diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 303d530c04..74423be757 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -472,6 +472,8 @@ void database::clear_expired_orders() void database::update_expired_feeds() { + auto head_time = head_block_time(); + auto next_maint_time = get_dynamic_global_properties().next_maintenance_time; auto& asset_idx = get_index_type().indices().get(); auto itr = asset_idx.lower_bound( true /** market issued */ ); while( itr != asset_idx.end() ) @@ -482,14 +484,14 @@ void database::update_expired_feeds() const asset_bitasset_data_object& b = a.bitasset_data(*this); bool feed_is_expired; - if( head_block_time() < HARDFORK_615_TIME ) - feed_is_expired = b.feed_is_expired_before_hardfork_615( head_block_time() ); + if( head_time < HARDFORK_615_TIME ) + feed_is_expired = b.feed_is_expired_before_hardfork_615( head_time ); else - feed_is_expired = b.feed_is_expired( head_block_time() ); + feed_is_expired = b.feed_is_expired( head_time ); if( feed_is_expired ) { - modify(b, [this](asset_bitasset_data_object& a) { - a.update_median_feeds(head_block_time()); + modify(b, [head_time,next_maint_time](asset_bitasset_data_object& a) { + a.update_median_feeds( head_time, next_maint_time ); }); check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); } diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index a15117b371..9631efb0e1 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -192,6 +192,10 @@ namespace graphene { namespace chain { /// This is the publication time of the oldest feed which was factored into current_feed. time_point_sec current_feed_publication_time; + /// Change on current_feed.maintenance_collateral_ratio will be pending here until next maintenance interval + /// (since hard fork core-935) + optional pending_maintenance_collateral_ratio; + /// True if this asset implements a @ref prediction_market bool is_prediction_market = false; @@ -222,13 +226,42 @@ namespace graphene { namespace chain { { return feed_expiration_time() >= current_time; } bool feed_is_expired(time_point_sec current_time)const { return feed_expiration_time() <= current_time; } - void update_median_feeds(time_point_sec current_time); + + /** + * @brief calculate the median feed + * + * This calculates the median feed. It sets the @ref current_feed_publication_time, + * @ref pending_maintenance_collateral_ratio and @ref current_feed member variables. + * + * @param current_time the time to use in the calculations + * @param next_maintenance_time The time to use to check if need to apply pending logic + */ + void update_median_feeds( time_point_sec current_time, time_point_sec next_maintenance_time ); + private: + /** + * Update @ref current_feed and @ref pending_maintenance_collateral_ratio with given parameters. + * @param new_feed New feed + * @param next_maintenance_time The time to use to check if need to apply pending logic + * @note this funtion will only be called by @update_median_feeds; @ref new_feed will be "moved" after called. + */ + void update_current_feed( price_feed& new_feed, time_point_sec next_maintenance_time ); + }; + struct by_pending_mcr; + typedef multi_index_container< asset_bitasset_data_object, indexed_by< - ordered_unique< tag, member< object, object_id_type, &object::id > > + ordered_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + composite_key< asset_bitasset_data_object, + member< asset_bitasset_data_object, + optional, + &asset_bitasset_data_object::pending_maintenance_collateral_ratio >, + member< object, object_id_type, &object::id > + > + > > > asset_bitasset_data_object_multi_index_type; typedef generic_index asset_bitasset_data_index; @@ -262,6 +295,7 @@ FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db:: (feeds) (current_feed) (current_feed_publication_time) + (pending_maintenance_collateral_ratio) (options) (force_settled_volume) (is_prediction_market) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 62fc529066..e005255d93 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -144,7 +144,7 @@ #define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4 #define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3 -#define GRAPHENE_CURRENT_DB_VERSION "BTS2.14" +#define GRAPHENE_CURRENT_DB_VERSION "BTS2.15" #define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT) From 591dcd4b8bddaba889094fc108d94c3be82db060 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 23 May 2018 20:51:16 -0400 Subject: [PATCH 05/13] Test cases for deferring MCR update #935 --- tests/tests/bitasset_tests.cpp | 98 ++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/tests/tests/bitasset_tests.cpp b/tests/tests/bitasset_tests.cpp index 6f9e5beedd..fdcaacf2e7 100644 --- a/tests/tests/bitasset_tests.cpp +++ b/tests/tests/bitasset_tests.cpp @@ -552,7 +552,8 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) ; generate_blocks( HARDFORK_615_TIME, true, skip ); // get around Graphene issue #615 feed expiration bug generate_blocks( db.get_dynamic_global_properties().next_maintenance_time, true, skip ); - generate_block( skip ); + for( int j = 0; j <= 10; ++j ) + generate_block( skip ); for( int i = 0; i < 3; ++i ) { @@ -588,7 +589,7 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) ba_op.asset_to_update = usd_id; ba_op.issuer = asset_to_update.issuer; ba_op.new_options = asset_to_update.bitasset_data(db).options; - ba_op.new_options.feed_lifetime_sec = 300; + ba_op.new_options.feed_lifetime_sec = 60; trx.operations.push_back(ba_op); PUSH_TX(db, trx, ~0); trx.clear(); @@ -603,32 +604,71 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) // prepare feed data price_feed current_feed; + auto default_mcr = current_feed.maintenance_collateral_ratio; + BOOST_REQUIRE( default_mcr != 3500 ); // assume default mcr is not 350% in this test case current_feed.maintenance_collateral_ratio = 3500; current_feed.maximum_short_squeeze_ratio = 1100; - // set 2 price feeds with 350% MCR + // set 2 price feeds with 350% MCR, median MCR would be 350% when in effect current_feed.settlement_price = asset(100, usd_id) / asset(5); publish_feed( usd_id, feedproducer_id, current_feed ); publish_feed( usd_id, feedproducer2_id, current_feed ); - // check median, MCR should be 350% + // check median BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + if( i < 2 ) // before hf 935, MCR should be 350% + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + else // after hf 935, MCR should be default_mcr, pending MCR should be 350% + { + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); + BOOST_CHECK( usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + BOOST_CHECK_EQUAL( *usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio, 3500 ); + } // generate some blocks, let the feeds expire - blocks += generate_blocks( db.head_block_time() + 360, true, skip ); + blocks += generate_blocks( db.head_block_time() + 90, true, skip ); set_expiration( db, trx ); // check median, should be null BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price.is_null() ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); - // publish a new feed with 175% MCR, new median MCR would be 175% + if( i == 2 ) + { + // generate some blocks to near next maintenance interval + blocks += generate_blocks( db.get_dynamic_global_properties().next_maintenance_time - 15, true, skip ); + set_expiration( db, trx ); + } + + // publish a new feed with 175% MCR, new median MCR would be 175% when in effect current_feed.maintenance_collateral_ratio = 1750; publish_feed( usd_id, feedproducer3_id, current_feed ); - // check median, MCR should be 175% + // check median + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + if( i < 2 ) // before hf 935, MCR should be 175% + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); + else // after hf 935, MCR should be default_mcr, pending MCR should be 175% if default is not 175% + { + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); + if( default_mcr != 1750 ) + { + BOOST_CHECK( usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + BOOST_CHECK_EQUAL( *usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio, 1750 ); + } + else + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + + // go to next maintenance interval + blocks += generate_blocks( db.get_dynamic_global_properties().next_maintenance_time, true, skip ); + set_expiration( db, trx ); + } + + // check median, median MCR should be 175% BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); // Place some collateralized orders // start out with 300% collateral, call price is 15/175 CORE/USD = 60/700 @@ -650,6 +690,7 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) ba_op.new_options = asset_to_update.bitasset_data(db).options; ba_op.new_options.feed_lifetime_sec = HARDFORK_CORE_935_TIME.sec_since_epoch() - db.head_block_time().sec_since_epoch() + + 3600 + mi * 3; trx.operations.push_back(ba_op); PUSH_TX(db, trx, ~0); @@ -673,7 +714,7 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) // after hard fork 890, if it's before hard fork 935 if( db.get_dynamic_global_properties().next_maintenance_time <= HARDFORK_CORE_935_TIME ) { - // median should have changed + // median should have changed, new MCR is 350% BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); // but the limit order is still there, because `check_call_order` was incorrectly skipped @@ -682,22 +723,45 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) // go beyond hard fork 935 blocks += generate_blocks(HARDFORK_CORE_935_TIME - mi, true, skip); blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); - } - // after hard fork 935, the limit order should be filled - { - // median MCR should be 350% + // median MCR is still 350% BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); - // the limit order is still there, because `check_call_order` is skipped + // the limit order should have been filled BOOST_CHECK( !db.find( sell_id ) ); - if( db.find( sell_id ) ) + } + else // already after hard fork 935 + { + if( i < 2 ) // hf 890 and hf 935 occurs at same time (since we won't let hf 890 occur earlier than hf 935) { - idump( (sell_id(db)) ); + // median MCR is 350% + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + // the limit order should have been filled + BOOST_CHECK( !db.find( sell_id ) ); + } + else // i == 2 + { + // MCR change is pending + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); + BOOST_CHECK( usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + BOOST_CHECK_EQUAL( *usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio, 3500 ); + // the limit order is still there + BOOST_CHECK( db.find( sell_id ) ); + + // generate more blocks, pass one more maintenance interval + blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); + + // median MCR should be 350% + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + // the limit order should have been filled + BOOST_CHECK( !db.find( sell_id ) ); } } - // undo above tx's and reset generate_block( skip ); ++blocks; From 79274c687af60b8e7d2305400b764064d7118d1b Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 23 May 2018 21:24:40 -0400 Subject: [PATCH 06/13] Keep old MCR when updating median feed to null --- libraries/chain/asset_object.cpp | 1 + tests/tests/bitasset_tests.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 45481079d0..ba725f83a8 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -66,6 +66,7 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds( time_poin //... don't calculate a median, and set a null feed current_feed_publication_time = current_time; price_feed null_feed; + null_feed.maintenance_collateral_ratio = current_feed.maintenance_collateral_ratio; // keep old MCR update_current_feed( null_feed, next_maintenance_time ); return; } diff --git a/tests/tests/bitasset_tests.cpp b/tests/tests/bitasset_tests.cpp index fdcaacf2e7..162461d46a 100644 --- a/tests/tests/bitasset_tests.cpp +++ b/tests/tests/bitasset_tests.cpp @@ -629,9 +629,14 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) blocks += generate_blocks( db.head_block_time() + 90, true, skip ); set_expiration( db, trx ); - // check median, should be null + // check median, settlement_price should be null BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price.is_null() ); - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); + // MCR should not change + if( i < 2 ) + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + else + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); + // pending MCR got reset BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); if( i == 2 ) From cf1c28086997b1f98db899f361e2e97f6d621bb6 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 23 May 2018 22:21:39 -0400 Subject: [PATCH 07/13] Don't defer MCR update when current_supply is zero --- libraries/chain/asset_evaluator.cpp | 26 ++++--- libraries/chain/asset_object.cpp | 14 ++-- libraries/chain/db_maint.cpp | 6 +- libraries/chain/db_update.cpp | 10 +-- .../graphene/chain/asset_evaluator.hpp | 4 ++ .../include/graphene/chain/asset_object.hpp | 8 +-- tests/tests/bitasset_tests.cpp | 67 ++++++++----------- 7 files changed, 69 insertions(+), 66 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index bc196f3ea9..0f1b99422d 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -464,7 +464,9 @@ static bool update_bitasset_object_options( if( should_update_feeds ) { const auto old_feed = bdo.current_feed; - bdo.update_median_feeds( db.head_block_time(), next_maint_time ); + bool defer_mcr_update = ( next_maint_time > HARDFORK_CORE_935_TIME + && asset_to_update.dynamic_data(db).current_supply > 0 ); + bdo.update_median_feeds( db.head_block_time(), defer_mcr_update ); // TODO review and refactor / cleanup after hard fork: // 1. if hf_core_868_890 and core-935 occurred at same time @@ -528,6 +530,7 @@ void_result asset_update_feed_producers_evaluator::do_evaluate(const asset_updat const asset_bitasset_data_object& b = a.bitasset_data(d); bitasset_to_update = &b; + asset_to_update = &a; FC_ASSERT( a.issuer == o.issuer ); return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } @@ -535,7 +538,9 @@ void_result asset_update_feed_producers_evaluator::do_evaluate(const asset_updat void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_feed_producers_evaluator::operation_type& o) { try { database& d = db(); - d.modify(*bitasset_to_update, [&d, &o](asset_bitasset_data_object& a) { + bool defer_mcr_update = ( d.get_dynamic_global_properties().next_maintenance_time > HARDFORK_CORE_935_TIME + && asset_to_update->dynamic_data(d).current_supply > 0 ); + d.modify(*bitasset_to_update, [&d, &o, defer_mcr_update](asset_bitasset_data_object& a) { //This is tricky because I have a set of publishers coming in, but a map of publisher to feed is stored. //I need to update the map such that the keys match the new publishers, but not munge the old price feeds from //publishers who are being kept. @@ -551,9 +556,9 @@ void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_f for( auto itr = o.new_feed_producers.begin(); itr != o.new_feed_producers.end(); ++itr ) if( !a.feeds.count(*itr) ) a.feeds[*itr]; - a.update_median_feeds( d.head_block_time(), d.get_dynamic_global_properties().next_maintenance_time ); + a.update_median_feeds( d.head_block_time(), defer_mcr_update ); }); - d.check_call_orders( o.asset_to_update(d) ); + d.check_call_orders( *asset_to_update ); return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } @@ -713,6 +718,9 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_ FC_ASSERT(bitasset.feeds.count(o.publisher)); } + asset_to_update = &base; + bitasset_to_update = &bitasset; + return void_result(); } FC_CAPTURE_AND_RETHROW((o)) } @@ -721,14 +729,16 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope database& d = db(); - const asset_object& base = o.asset_id(d); - const asset_bitasset_data_object& bad = base.bitasset_data(d); + const asset_object& base = *asset_to_update; + const asset_bitasset_data_object& bad = *bitasset_to_update; + bool defer_mcr_update = ( d.get_dynamic_global_properties().next_maintenance_time > HARDFORK_CORE_935_TIME + && base.dynamic_data(d).current_supply > 0 ); auto old_feed = bad.current_feed; // Store medians for this asset - d.modify(bad , [&o,&d](asset_bitasset_data_object& a) { + d.modify(bad , [&o, &d, defer_mcr_update](asset_bitasset_data_object& a) { a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed); - a.update_median_feeds( d.head_block_time(), d.get_dynamic_global_properties().next_maintenance_time ); + a.update_median_feeds( d.head_block_time(), defer_mcr_update ); }); if( !(old_feed == bad.current_feed) ) diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index ba725f83a8..085cf4b7e1 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -44,8 +44,7 @@ share_type asset_bitasset_data_object::max_force_settlement_volume(share_type cu return volume.to_uint64(); } -void graphene::chain::asset_bitasset_data_object::update_median_feeds( time_point_sec current_time, - time_point_sec next_maintenance_time ) +void graphene::chain::asset_bitasset_data_object::update_median_feeds( time_point_sec current_time, bool defer_mcr_update ) { current_feed_publication_time = current_time; vector> current_feeds; @@ -67,13 +66,13 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds( time_poin current_feed_publication_time = current_time; price_feed null_feed; null_feed.maintenance_collateral_ratio = current_feed.maintenance_collateral_ratio; // keep old MCR - update_current_feed( null_feed, next_maintenance_time ); + update_current_feed( null_feed, defer_mcr_update ); return; } if( current_feeds.size() == 1 ) { price_feed only_feed = std::move( current_feeds.front() ); - update_current_feed( only_feed, next_maintenance_time ); + update_current_feed( only_feed, defer_mcr_update ); return; } @@ -91,13 +90,12 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds( time_poin #undef CALCULATE_MEDIAN_VALUE // *** End Median Calculations *** - update_current_feed( median_feed, next_maintenance_time ); + update_current_feed( median_feed, defer_mcr_update ); } -void graphene::chain::asset_bitasset_data_object::update_current_feed( price_feed& new_feed, - time_point_sec next_maintenance_time ) +void graphene::chain::asset_bitasset_data_object::update_current_feed( price_feed& new_feed, bool defer_mcr_update ) { - if( next_maintenance_time > HARDFORK_CORE_935_TIME ) + if( defer_mcr_update ) { if( current_feed.maintenance_collateral_ratio == new_feed.maintenance_collateral_ratio ) pending_maintenance_collateral_ratio.reset(); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index f5f9541545..0311f50d7f 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -958,8 +958,10 @@ void process_hf_868_890( database& db, bool skip_check_call_orders, time_point_s } // always update the median feed due to https://github.com/bitshares/bitshares-core/issues/890 - db.modify( bitasset_data, [head_time,next_maintenance_time]( asset_bitasset_data_object &obj ) { - obj.update_median_feeds( head_time, next_maintenance_time ); + bool defer_mcr_update = ( next_maintenance_time > HARDFORK_CORE_935_TIME + && current_asset.dynamic_data(db).current_supply > 0 ); + db.modify( bitasset_data, [head_time,defer_mcr_update]( asset_bitasset_data_object &obj ) { + obj.update_median_feeds( head_time, defer_mcr_update ); }); bool median_changed = ( old_feed.settlement_price != bitasset_data.current_feed.settlement_price ); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 74423be757..c4d272495b 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -490,15 +490,17 @@ void database::update_expired_feeds() feed_is_expired = b.feed_is_expired( head_time ); if( feed_is_expired ) { - modify(b, [head_time,next_maint_time](asset_bitasset_data_object& a) { - a.update_median_feeds( head_time, next_maint_time ); + bool defer_mcr_update = ( next_maint_time > HARDFORK_CORE_935_TIME + && a.dynamic_data(*this).current_supply > 0 ); + modify(b, [head_time,defer_mcr_update](asset_bitasset_data_object& abdo) { + abdo.update_median_feeds( head_time, defer_mcr_update ); }); check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); } if( !b.current_feed.core_exchange_rate.is_null() && a.options.core_exchange_rate != b.current_feed.core_exchange_rate ) - modify(a, [&b](asset_object& a) { - a.options.core_exchange_rate = b.current_feed.core_exchange_rate; + modify(a, [&b](asset_object& ao) { + ao.options.core_exchange_rate = b.current_feed.core_exchange_rate; }); } } diff --git a/libraries/chain/include/graphene/chain/asset_evaluator.hpp b/libraries/chain/include/graphene/chain/asset_evaluator.hpp index 7ab6cfdab4..f9dd19e118 100644 --- a/libraries/chain/include/graphene/chain/asset_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/asset_evaluator.hpp @@ -113,6 +113,7 @@ namespace graphene { namespace chain { void_result do_apply( const operation_type& o ); const asset_bitasset_data_object* bitasset_to_update = nullptr; + const asset_object* asset_to_update = nullptr; }; class asset_fund_fee_pool_evaluator : public evaluator @@ -156,6 +157,9 @@ namespace graphene { namespace chain { void_result do_apply( const asset_publish_feed_operation& o ); std::map,price_feed> median_feed_values; + + const asset_bitasset_data_object* bitasset_to_update = nullptr; + const asset_object* asset_to_update = nullptr; }; class asset_claim_fees_evaluator : public evaluator diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 9631efb0e1..94e7f51e29 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -234,17 +234,17 @@ namespace graphene { namespace chain { * @ref pending_maintenance_collateral_ratio and @ref current_feed member variables. * * @param current_time the time to use in the calculations - * @param next_maintenance_time The time to use to check if need to apply pending logic + * @param defer_mcr_update set to true to defer MCR update to next maintenance interval */ - void update_median_feeds( time_point_sec current_time, time_point_sec next_maintenance_time ); + void update_median_feeds( time_point_sec current_time, bool defer_mcr_update ); private: /** * Update @ref current_feed and @ref pending_maintenance_collateral_ratio with given parameters. * @param new_feed New feed - * @param next_maintenance_time The time to use to check if need to apply pending logic + * @param defer_mcr_update set to true to defer MCR update to next maintenance interval * @note this funtion will only be called by @update_median_feeds; @ref new_feed will be "moved" after called. */ - void update_current_feed( price_feed& new_feed, time_point_sec next_maintenance_time ); + void update_current_feed( price_feed& new_feed, bool defer_mcr_update ); }; diff --git a/tests/tests/bitasset_tests.cpp b/tests/tests/bitasset_tests.cpp index 162461d46a..9446910dd9 100644 --- a/tests/tests/bitasset_tests.cpp +++ b/tests/tests/bitasset_tests.cpp @@ -616,14 +616,8 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) // check median BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); - if( i < 2 ) // before hf 935, MCR should be 350% - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); - else // after hf 935, MCR should be default_mcr, pending MCR should be 350% - { - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); - BOOST_CHECK( usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); - BOOST_CHECK_EQUAL( *usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio, 3500 ); - } + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); // generate some blocks, let the feeds expire blocks += generate_blocks( db.head_block_time() + 90, true, skip ); @@ -632,44 +626,13 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) // check median, settlement_price should be null BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price.is_null() ); // MCR should not change - if( i < 2 ) - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); - else - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); - // pending MCR got reset + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); - if( i == 2 ) - { - // generate some blocks to near next maintenance interval - blocks += generate_blocks( db.get_dynamic_global_properties().next_maintenance_time - 15, true, skip ); - set_expiration( db, trx ); - } - // publish a new feed with 175% MCR, new median MCR would be 175% when in effect current_feed.maintenance_collateral_ratio = 1750; publish_feed( usd_id, feedproducer3_id, current_feed ); - // check median - BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); - if( i < 2 ) // before hf 935, MCR should be 175% - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); - else // after hf 935, MCR should be default_mcr, pending MCR should be 175% if default is not 175% - { - BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, default_mcr ); - if( default_mcr != 1750 ) - { - BOOST_CHECK( usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); - BOOST_CHECK_EQUAL( *usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio, 1750 ); - } - else - BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); - - // go to next maintenance interval - blocks += generate_blocks( db.get_dynamic_global_properties().next_maintenance_time, true, skip ); - set_expiration( db, trx ); - } - // check median, median MCR should be 175% BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 1750 ); @@ -764,6 +727,30 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); // the limit order should have been filled BOOST_CHECK( !db.find( sell_id ) ); + + // publish a new feed with feedproducer2 at 175% MCR + publish_feed( usd_id, feedproducer2_id, current_feed ); + // median MCR should be 350%, pending 175% + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + BOOST_CHECK( usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + BOOST_CHECK_EQUAL( *usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio, 1750 ); + + // publish a new feed with feedproducer2 at 350% MCR + current_feed.maintenance_collateral_ratio = 3500; + publish_feed( usd_id, feedproducer2_id, current_feed ); + // median MCR should be 350%, no pending + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + + // generate more blocks, pass one more maintenance interval + blocks += generate_blocks(db.get_dynamic_global_properties().next_maintenance_time, true, skip); + // median MCR should be 350%, no pending + BOOST_CHECK( usd_id(db).bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price ); + BOOST_CHECK_EQUAL( usd_id(db).bitasset_data(db).current_feed.maintenance_collateral_ratio, 3500 ); + BOOST_CHECK( !usd_id(db).bitasset_data(db).pending_maintenance_collateral_ratio.valid() ); + } } From 02e556a5197c0319650ef32b794fb6f6f607dbae Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 24 May 2018 08:47:49 -0400 Subject: [PATCH 08/13] Update logging --- libraries/chain/db_maint.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 0311f50d7f..80258b84a2 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -773,8 +773,16 @@ void database::process_bids( const asset_bitasset_data_object& bad ) */ void update_and_match_call_orders( database& db, const asset_bitasset_data_object* bitasset = nullptr ) { + const auto head_num = db.head_block_num(); + const asset_object* asset_obj; if( !bitasset ) - wlog( "Updating all call orders for hardfork core-343/935 at block ${n}", ("n",db.head_block_num()) ); + wlog( "Updating all call orders for hardfork core-343/935 at block ${n}", ("n",head_num) ); + else + { + asset_obj = &bitasset->asset_id(db); + wlog( "Updating all call orders for asset ${sym} (${aid}) due to MCR change at block ${n}", + ("aid",asset_obj->get_id())("sym",asset_obj->symbol)("n",head_num) ); + } // Update call_price asset_id_type current_asset = bitasset ? bitasset->asset_id : asset_id_type(); @@ -804,7 +812,11 @@ void update_and_match_call_orders( database& db, const asset_bitasset_data_objec // Match call orders if( bitasset ) - db.check_call_orders( current_asset(db), true, false ); // allow black swan, and call orders are taker + { + db.check_call_orders( *asset_obj, true, false ); // allow black swan, and call orders are taker + wlog( "Done updating all call orders for asset ${sym} (${aid}) due to MCR change at block ${n}", + ("aid",asset_obj->get_id())("sym",asset_obj->symbol)("n",head_num) ); + } else { const auto& asset_idx = db.get_index_type().indices().get(); @@ -816,7 +828,7 @@ void update_and_match_call_orders( database& db, const asset_bitasset_data_objec // 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/935 at block ${n}", ("n",db.head_block_num()) ); + wlog( "Done updating all call orders for hardfork core-343/935 at block ${n}", ("n",head_num) ); } } @@ -826,11 +838,16 @@ void update_and_match_call_orders( database& db, const asset_bitasset_data_objec */ void process_pending_mcr( database& db ) { + const auto head_num = db.head_block_num(); const auto& bitasset_idx = db.get_index_type().indices().get(); auto ba_itr = bitasset_idx.upper_bound( optional() ); // has something pending while( ba_itr != bitasset_idx.end() ) { const asset_bitasset_data_object& abd = *ba_itr; + wlog( "Updating MCR from ${old} to ${new} for bitasset ${bid} / asset ${aid} at block ${n}", + ("old",abd.current_feed.maintenance_collateral_ratio) + ("new",abd.pending_maintenance_collateral_ratio) + ("bid",ba_itr->id)("aid",abd.asset_id)("n",head_num) ); ++ba_itr; db.modify( abd, []( asset_bitasset_data_object& abdo ) { From 4f87239cbfa1fac98f99496fb4721ddb611bf03c Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 24 May 2018 09:01:11 -0400 Subject: [PATCH 09/13] Logging when incorrectly skipped check_call_orders --- libraries/chain/db_maint.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 80258b84a2..8efddab966 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -989,14 +989,20 @@ void process_hf_868_890( database& db, bool skip_check_call_orders, time_point_s ("asset_sym", current_asset.symbol)("asset_id", current_asset.id) ); } - // Note: due to bitshares-core issue #935, this check below (using median_changed) is incorrect. + // Note: due to bitshares-core issue #935, the check below (using median_changed) is incorrect. // However, `skip_check_call_orders` will likely be true in both testnet and mainnet, // so effectively the incorrect code won't make a difference. + // Additionally, we have code to update all call orders again during hardfork core-935 // TODO cleanup after hard fork if( !skip_check_call_orders && median_changed ) // check_call_orders should be called { db.check_call_orders( current_asset ); } + else if( !skip_check_call_orders && median_feed_changed ) + { + wlog( "Incorrectly skipped check_call_orders for asset ${asset_sym} (${asset_id}) during hardfork core-868-890", + ("asset_sym", current_asset.symbol)("asset_id", current_asset.id) ); + } } // for each market issued asset } From 138bf62772e4f5e48b45aaea8563313a6f32efe4 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 24 May 2018 09:09:44 -0400 Subject: [PATCH 10/13] Update logging --- libraries/chain/db_maint.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 8efddab966..2360664bd7 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -918,7 +918,9 @@ void database::process_bitassets() // * NOTE: the removal can't be applied to testnet void process_hf_868_890( database& db, bool skip_check_call_orders, time_point_sec next_maintenance_time ) { - auto head_time = db.head_block_time(); + const auto head_time = db.head_block_time(); + const auto head_num = db.head_block_num(); + wlog( "Processing hard fork core-868-890 at block ${n}", ("n",head_num) ); // for each market issued asset const auto& asset_idx = db.get_index_type().indices().get(); for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_idx.end(); ++asset_itr ) @@ -1004,6 +1006,7 @@ void process_hf_868_890( database& db, bool skip_check_call_orders, time_point_s ("asset_sym", current_asset.symbol)("asset_id", current_asset.id) ); } } // for each market issued asset + wlog( "Done processing hard fork core-868-890 at block ${n}", ("n",head_num) ); } void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) From b78245049f9d9d536597a95ade1582e64bfa5db9 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 24 May 2018 09:19:09 -0400 Subject: [PATCH 11/13] Fix compiler warning --- libraries/chain/db_maint.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 2360664bd7..8ce89c04ae 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -774,7 +774,7 @@ void database::process_bids( const asset_bitasset_data_object& bad ) void update_and_match_call_orders( database& db, const asset_bitasset_data_object* bitasset = nullptr ) { const auto head_num = db.head_block_num(); - const asset_object* asset_obj; + const asset_object* asset_obj = nullptr; if( !bitasset ) wlog( "Updating all call orders for hardfork core-343/935 at block ${n}", ("n",head_num) ); else @@ -813,6 +813,7 @@ void update_and_match_call_orders( database& db, const asset_bitasset_data_objec // Match call orders if( bitasset ) { + // Note: asset_obj should have been updated earlier, so will be valid db.check_call_orders( *asset_obj, true, false ); // allow black swan, and call orders are taker wlog( "Done updating all call orders for asset ${sym} (${aid}) due to MCR change at block ${n}", ("aid",asset_obj->get_id())("sym",asset_obj->symbol)("n",head_num) ); From 9c39c95c634691f9110436d31d3ed29a3e4ae9c8 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 24 May 2018 09:31:31 -0400 Subject: [PATCH 12/13] Update comments --- libraries/chain/db_maint.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 8ce89c04ae..308e0f2da2 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -769,7 +769,7 @@ void database::process_bids( const asset_bitasset_data_object& bad ) /** * @brief Update and match call orders * @param db The database - * @param bitasset set to `nullptr` to update all call orders, otherwise only update call orders of this asset + * @param bitasset set to `nullptr` to update call orders of all assets, otherwise only update call orders of this asset */ void update_and_match_call_orders( database& db, const asset_bitasset_data_object* bitasset = nullptr ) { @@ -785,6 +785,8 @@ void update_and_match_call_orders( database& db, const asset_bitasset_data_objec } // Update call_price + + // Save variables outside of the iteration for better performance asset_id_type current_asset = bitasset ? bitasset->asset_id : asset_id_type(); const asset_bitasset_data_object* abd = bitasset; @@ -798,7 +800,7 @@ void update_and_match_call_orders( database& db, const asset_bitasset_data_objec { const call_order_object& call_obj = *citr; ++citr; - if( !bitasset && current_asset != call_obj.debt_type() ) // only do this when updating all call orders + if( !bitasset && current_asset != call_obj.debt_type() ) // only do this when updating call orders of all assets { // debt type won't be asset_id_type(), so abd will always get initialized current_asset = call_obj.debt_type(); abd = ¤t_asset(db).bitasset_data(db); From 2d44470bf715e1953d1db18e7321a7e0c6e99c88 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 24 May 2018 10:04:03 -0400 Subject: [PATCH 13/13] Remove unnecessary header inclusion --- libraries/chain/asset_object.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 085cf4b7e1..e390029d94 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -23,7 +23,6 @@ */ #include #include -#include #include