From 8a9d3e77756df6ba163e6907c89f3e387fe92191 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 1 Jul 2018 15:01:31 -0400 Subject: [PATCH 01/17] Added logging for the old update_expired_feeds bug The old bug is https://github.com/cryptonomex/graphene/issues/615 . Due to the bug, `update_median_feeds()` and `check_call_orders()` will be called when a feed is not actually expired, normally this should not affect consensus since calling them should not change any data in the state. However, the logging indicates that `check_call_orders()` did change some data under certain circumstances, specifically, when multiple limit order matching issue (#453) occurred at same block. * https://github.com/bitshares/bitshares-core/issues/453 --- libraries/chain/db_update.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 7df02a39..66825982 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -466,6 +466,9 @@ void database::clear_expired_orders() void database::update_expired_feeds() { + const auto head_num = head_block_num(); + const auto head_time = head_block_time(); + bool before_hf_615 = ( head_time < HARDFORK_615_TIME ); auto& asset_idx = get_index_type().indices().get(); auto itr = asset_idx.lower_bound( true /** market issued */ ); while( itr != asset_idx.end() ) @@ -476,16 +479,21 @@ 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( before_hf_615 ) + 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](asset_bitasset_data_object& a) { + a.update_median_feeds(head_time); }); - check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); + bool called_some = check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); + if( called_some && before_hf_615 ) + { + wlog( "Graphene issue #615: called some for asset ${a} on block #${b}, feed really expired: ${f}", + ("a", a.symbol) ("b", head_num) ("f", b.feed_is_expired(head_time)) ); + } } if( !b.current_feed.core_exchange_rate.is_null() && a.options.core_exchange_rate != b.current_feed.core_exchange_rate ) From 01a81554ff79bb446b21650fe9b64cc78df28e40 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 3 Jul 2018 12:24:25 -0400 Subject: [PATCH 02/17] Minor performance improvement for price::is_null() --- libraries/chain/protocol/asset.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/chain/protocol/asset.cpp b/libraries/chain/protocol/asset.cpp index e1169b0c..c47d88e3 100644 --- a/libraries/chain/protocol/asset.cpp +++ b/libraries/chain/protocol/asset.cpp @@ -130,7 +130,11 @@ namespace graphene { namespace chain { return ~(asset( cp.numerator().convert_to(), debt.asset_id ) / asset( cp.denominator().convert_to(), collateral.asset_id )); } FC_CAPTURE_AND_RETHROW( (debt)(collateral)(collateral_ratio) ) } - bool price::is_null() const { return *this == price(); } + bool price::is_null() const + { + // Effectively same as "return *this == price();" but perhaps faster + return ( base.asset_id == asset_id_type() && quote.asset_id == asset_id_type() ); + } void price::validate() const { try { From cabbd7d07065f8c68cc477432b97c5931754f8c6 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 3 Jul 2018 12:25:36 -0400 Subject: [PATCH 03/17] Use static refs in db_getter for immutable objects --- libraries/chain/db_getter.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index d2be25de..c9b20136 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -37,22 +37,26 @@ namespace graphene { namespace chain { const asset_object& database::get_core_asset() const { - return get(asset_id_type()); + static const asset_object& obj = get(asset_id_type()); + return obj; } const global_property_object& database::get_global_properties()const { - return get( global_property_id_type() ); + static const global_property_object& obj = get( global_property_id_type() ); + return obj; } const chain_property_object& database::get_chain_properties()const { - return get( chain_property_id_type() ); + static const chain_property_object& obj = get( chain_property_id_type() ); + return obj; } const dynamic_global_property_object& database::get_dynamic_global_properties() const { - return get( dynamic_global_property_id_type() ); + static const dynamic_global_property_object& obj = get( dynamic_global_property_id_type() ); + return obj; } const fee_schedule& database::current_fee_schedule()const @@ -62,17 +66,17 @@ const fee_schedule& database::current_fee_schedule()const time_point_sec database::head_block_time()const { - return get( dynamic_global_property_id_type() ).time; + return get_dynamic_global_properties().time; } uint32_t database::head_block_num()const { - return get( dynamic_global_property_id_type() ).head_block_number; + return get_dynamic_global_properties().head_block_number; } block_id_type database::head_block_id()const { - return get( dynamic_global_property_id_type() ).head_block_id; + return get_dynamic_global_properties().head_block_id; } decltype( chain_parameters::block_interval ) database::block_interval( )const From ac7ac9f1f219f829d0fe7c7ae630c6bdd5fd8980 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 3 Jul 2018 12:39:50 -0400 Subject: [PATCH 04/17] Minor performance improvement for db_maint --- libraries/chain/db_maint.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 1ade420a..2b386633 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -151,12 +151,13 @@ void database::update_worker_votes() void database::pay_workers( share_type& budget ) { + const auto head_time = head_block_time(); // ilog("Processing payroll! Available budget is ${b}", ("b", budget)); vector> active_workers; - get_index_type().inspect_all_objects([this, &active_workers](const object& o) { + // TODO optimization: add by_expiration index to avoid iterating through all objects + get_index_type().inspect_all_objects([head_time, &active_workers](const object& o) { const worker_object& w = static_cast(o); - auto now = head_block_time(); - if( w.is_active(now) && w.approving_stake() > 0 ) + if( w.is_active(head_time) && w.approving_stake() > 0 ) active_workers.emplace_back(w); }); @@ -170,15 +171,21 @@ void database::pay_workers( share_type& budget ) return wa.id < wb.id; }); + const auto last_budget_time = get_dynamic_global_properties().last_budget_time; + const auto passed_time_ms = head_time - last_budget_time; + const bool passed_time_is_a_day = ( passed_time_ms == fc::days(1) ); + // the variable above is more likely false on BitShares mainnet, so do calculations below anyway + const auto passed_time_count = passed_time_ms.count(); + const auto day_count = fc::days(1).count(); for( uint32_t i = 0; i < active_workers.size() && budget > 0; ++i ) { const worker_object& active_worker = active_workers[i]; share_type requested_pay = active_worker.daily_pay; - if( head_block_time() - get_dynamic_global_properties().last_budget_time != fc::days(1) ) + if( !passed_time_is_a_day ) { fc::uint128 pay(requested_pay.value); - pay *= (head_block_time() - get_dynamic_global_properties().last_budget_time).count(); - pay /= fc::days(1).count(); + pay *= passed_time_count; + pay /= day_count; requested_pay = pay.to_uint64(); } @@ -1587,9 +1594,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g update_active_committee_members(); update_worker_votes(); - modify(gpo, [this](global_property_object& p) { + const dynamic_global_property_object& dgpo = get_dynamic_global_properties(); + + modify(gpo, [&dgpo](global_property_object& p) { // Remove scaling of account registration fee - const auto& dgpo = get_dynamic_global_properties(); p.parameters.current_fees->get().basic_fee >>= p.parameters.account_fee_scale_bitshifts * (dgpo.accounts_registered_this_interval / p.parameters.accounts_per_fee_scale); @@ -1610,7 +1618,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g } }); - auto next_maintenance_time = get(dynamic_global_property_id_type()).next_maintenance_time; + auto next_maintenance_time = dgpo.next_maintenance_time; auto maintenance_interval = gpo.parameters.maintenance_interval; if( next_maintenance_time <= next_block.timestamp ) @@ -1640,8 +1648,6 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g } } - const dynamic_global_property_object& dgpo = get_dynamic_global_properties(); - if( (dgpo.next_maintenance_time < HARDFORK_613_TIME) && (next_maintenance_time >= HARDFORK_613_TIME) ) deprecate_annual_members(*this); From e27b074f6250c13cfe48d1aa94d04d92c6d78825 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 3 Jul 2018 13:19:38 -0400 Subject: [PATCH 05/17] Minor code updates for asset_evaluator.cpp * changed an `assert()` to `FC_ASSERT()` * replaced one `db.get(asset_id_type())` with `db.get_core_asset()` * capture only required variables for lambda --- libraries/chain/asset_evaluator.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 59b590dd..e51ccc1a 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -137,17 +137,17 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o bool hf_429 = fee_is_odd && db().head_block_time() > HARDFORK_CORE_429_TIME; const asset_dynamic_data_object& dyn_asset = - db().create( [&]( asset_dynamic_data_object& a ) { + db().create( [hf_429,this]( asset_dynamic_data_object& a ) { a.current_supply = 0; a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0); }); - if( fee_is_odd && !hf_429 ) - { - const auto& core_dd = db().get( asset_id_type() ).dynamic_data( db() ); - db().modify( core_dd, [=]( asset_dynamic_data_object& dd ) { + if( fee_is_odd && !hf_429 ) + { + const auto& core_dd = db().get_core_asset().dynamic_data( db() ); + db().modify( core_dd, []( asset_dynamic_data_object& dd ) { dd.current_supply++; - }); - } + }); + } asset_bitasset_data_id_type bit_asset_id; if( op.bitasset_opts.valid() ) @@ -299,7 +299,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre asset_bitasset_data_id_type bit_asset_id; if( op.bitasset_opts.valid() ) - bit_asset_id = db().create( [&]( asset_bitasset_data_object& a ) { + bit_asset_id = db().create( [&op,next_asset_id]( asset_bitasset_data_object& a ) { a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; }).id; @@ -307,7 +307,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre auto next_asset_id = db().get_index_type().get_next_id(); const asset_object& new_asset = - db().create( [&]( asset_object& a ) { + db().create( [&op,next_asset_id,&dyn_asset,bit_asset_id]( asset_object& a ) { a.issuer = op.issuer; a.symbol = op.symbol; a.precision = op.precision; @@ -327,7 +327,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre if( op.bitasset_opts.valid() ) a.bitasset_data_id = bit_asset_id; }); - assert( new_asset.id == next_asset_id ); + FC_ASSERT( new_asset.id == next_asset_id ); return new_asset.id; } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -354,7 +354,7 @@ void_result asset_issue_evaluator::do_apply( const asset_issue_operation& o ) { try { db().adjust_balance( o.issue_to_account, o.asset_to_issue ); - db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ){ + db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ){ data.current_supply += o.asset_to_issue.amount; }); @@ -386,7 +386,7 @@ void_result asset_reserve_evaluator::do_apply( const asset_reserve_operation& o { try { db().adjust_balance( o.payer, -o.amount_to_reserve ); - db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ){ + db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ){ data.current_supply -= o.amount_to_reserve.amount; }); @@ -408,7 +408,7 @@ void_result asset_fund_fee_pool_evaluator::do_apply(const asset_fund_fee_pool_op { try { db().adjust_balance(o.from_account, -o.amount); - db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ) { + db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ) { data.fee_pool += o.amount; }); @@ -483,7 +483,7 @@ void_result asset_update_evaluator::do_apply(const asset_update_operation& o) d.cancel_order(*itr); } - d.modify(*asset_to_update, [&](asset_object& a) { + d.modify(*asset_to_update, [&o](asset_object& a) { if( o.new_issuer ) a.issuer = *o.new_issuer; a.options = o.new_options; From 36e318a50308c2e5d02f8b1b5581ae0c74055ff7 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 3 Jul 2018 13:32:08 -0400 Subject: [PATCH 06/17] Improve update_expired_feeds performance #1093 --- libraries/chain/asset_evaluator.cpp | 26 ++++- libraries/chain/asset_object.cpp | 5 + libraries/chain/db_block.cpp | 5 +- libraries/chain/db_market.cpp | 21 +++- libraries/chain/db_update.cpp | 104 +++++++++++++----- .../include/graphene/chain/asset_object.hpp | 46 +++++++- .../chain/include/graphene/chain/database.hpp | 9 +- 7 files changed, 170 insertions(+), 46 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index e51ccc1a..21378ce1 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -149,15 +149,16 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o }); } + auto next_asset_id = db().get_index_type().get_next_id(); + asset_bitasset_data_id_type bit_asset_id; if( op.bitasset_opts.valid() ) bit_asset_id = db().create( [&]( asset_bitasset_data_object& a ) { a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; + a.asset_id = next_asset_id; }).id; - auto next_asset_id = db().get_index_type().get_next_id(); - const asset_object& new_asset = db().create( [&]( asset_object& a ) { a.issuer = op.issuer; @@ -297,17 +298,18 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre }); } + auto next_asset_id = db().get_index_type().get_next_id(); + asset_bitasset_data_id_type bit_asset_id; if( op.bitasset_opts.valid() ) bit_asset_id = db().create( [&op,next_asset_id]( asset_bitasset_data_object& a ) { a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; + a.asset_id = next_asset_id; }).id; - auto next_asset_id = db().get_index_type().get_next_id(); - const asset_object& new_asset = - db().create( [&op,next_asset_id,&dyn_asset,bit_asset_id]( asset_object& a ) { + db().create( [&op,next_asset_id,&dyn_asset,bit_asset_id,this]( asset_object& a ) { a.issuer = op.issuer; a.symbol = op.symbol; a.precision = op.precision; @@ -483,6 +485,20 @@ void_result asset_update_evaluator::do_apply(const asset_update_operation& o) d.cancel_order(*itr); } + // For market-issued assets, if core change rate changed, update flag in bitasset data + if( asset_to_update->is_market_issued() + && asset_to_update->options.core_exchange_rate != o.new_options.core_exchange_rate ) + { + const auto& bitasset = asset_to_update->bitasset_data(d); + if( !bitasset.asset_cer_updated ) + { + d.modify( bitasset, [](asset_bitasset_data_object& b) + { + b.asset_cer_updated = true; + }); + } + } + d.modify(*asset_to_update, [&o](asset_object& a) { if( o.new_issuer ) a.issuer = *o.new_issuer; diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 63df70a3..ea387932 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -61,12 +61,15 @@ void asset_bitasset_data_object::update_median_feeds(time_point_sec current_time if( current_feeds.size() < options.minimum_feeds ) { //... don't calculate a median, and set a null feed + feed_cer_updated = false; // new median cer is null, won't update asset_object anyway, set to false for better performance current_feed_publication_time = current_time; current_feed = price_feed(); return; } if( current_feeds.size() == 1 ) { + if( current_feed.core_exchange_rate != current_feeds.front().get().core_exchange_rate ) + feed_cer_updated = true; current_feed = std::move(current_feeds.front()); return; } @@ -85,6 +88,8 @@ void asset_bitasset_data_object::update_median_feeds(time_point_sec current_time #undef CALCULATE_MEDIAN_VALUE // *** End Median Calculations *** + if( current_feed.core_exchange_rate != median_feed.core_exchange_rate ) + feed_cer_updated = true; current_feed = median_feed; } diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 1ad84fa0..45d75fa5 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -592,7 +592,7 @@ void database::_apply_block( const signed_block& next_block ) const witness_object& signing_witness = validate_block_header(skip, next_block); const auto& global_props = get_global_properties(); - const auto& dynamic_global_props = get(dynamic_global_property_id_type()); + const auto& dynamic_global_props = get_dynamic_global_properties(); bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.timestamp); _current_block_num = next_block_num; @@ -600,6 +600,8 @@ void database::_apply_block( const signed_block& next_block ) _current_op_in_trx = 0; _current_virtual_op = 0; + _issue_453_affected_assets.clear(); + for( const auto& trx : next_block.transactions ) { /* We do not need to push the undo state for each transaction @@ -639,6 +641,7 @@ void database::_apply_block( const signed_block& next_block ) clear_expired_proposals(); clear_expired_orders(); update_expired_feeds(); + update_core_exchange_rates(); update_withdraw_permissions(); update_tournaments(); update_betting_markets(next_block.timestamp); diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index 59f77762..77acedd3 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -426,14 +426,18 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa * * @return true if a margin call was executed. */ -bool database::check_call_orders(const asset_object& mia, bool enable_black_swan) +bool database::check_call_orders( const asset_object& mia, bool enable_black_swan, bool for_new_limit_order, + const asset_bitasset_data_object* bitasset_ptr ) { try { + static const auto& dyn_prop = get_dynamic_global_properties(); if( !mia.is_market_issued() ) return false; + auto maint_time = dyn_prop.next_maintenance_time; - if( check_for_blackswan( mia, enable_black_swan ) ) + const asset_bitasset_data_object& bitasset = ( bitasset_ptr ? *bitasset_ptr : mia.bitasset_data(*this) ); + + if( check_for_blackswan( mia, enable_black_swan, &bitasset ) ) return false; - const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this); if( bitasset.is_prediction_market ) return false; if( bitasset.current_feed.settlement_price.is_null() ) return false; @@ -464,7 +468,13 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan bool filled_limit = false; bool margin_called = false; - while( !check_for_blackswan( mia, enable_black_swan ) && call_itr != call_end ) + auto head_time = head_block_time(); + auto head_num = head_block_num(); + + bool before_hardfork_615 = ( head_time < HARDFORK_615_TIME ); + bool after_hardfork_436 = ( head_time > HARDFORK_436_TIME ); + + while( !check_for_blackswan( mia, enable_black_swan, &bitasset ) && call_itr != call_end ) { bool filled_call = false; price match_price; @@ -506,7 +516,8 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan if( usd_to_buy * match_price > call_itr->get_collateral() ) { - elog( "black swan detected" ); + elog( "black swan detected on asset ${symbol} (${id}) at block ${b}", + ("id",mia.id)("symbol",mia.symbol)("b",head_num) ); edump((enable_black_swan)); FC_ASSERT( enable_black_swan ); globally_settle_asset(mia, bitasset.current_feed.settlement_price ); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 66825982..eb4acd0d 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -121,6 +121,7 @@ void database::update_last_irreversible_block() const global_property_object& gpo = get_global_properties(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + // TODO for better performance, move this to db_maint, because only need to do it once per maintenance interval vector< const witness_object* > wit_objs; wit_objs.reserve( gpo.active_witnesses.size() ); for( const witness_id_type& wid : gpo.active_witnesses ) @@ -237,11 +238,12 @@ void database::clear_expired_proposals() * * A black swan occurs if MAX(HB,SP) <= LC */ -bool database::check_for_blackswan( const asset_object& mia, bool enable_black_swan ) +bool database::check_for_blackswan( const asset_object& mia, bool enable_black_swan, + const asset_bitasset_data_object* bitasset_ptr ) { if( !mia.is_market_issued() ) return false; - const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this); + const asset_bitasset_data_object& bitasset = ( bitasset_ptr ? *bitasset_ptr : mia.bitasset_data(*this) ); if( bitasset.has_settlement() ) return true; // already force settled auto settle_price = bitasset.current_feed.settlement_price; if( settle_price.is_null() ) return false; // no feed @@ -466,40 +468,84 @@ void database::clear_expired_orders() void database::update_expired_feeds() { - const auto head_num = head_block_num(); const auto head_time = head_block_time(); - bool before_hf_615 = ( head_time < HARDFORK_615_TIME ); - auto& asset_idx = 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; - assert( a.is_market_issued() ); + bool after_hardfork_615 = ( head_time >= HARDFORK_615_TIME ); - const asset_bitasset_data_object& b = a.bitasset_data(*this); - bool feed_is_expired; - if( before_hf_615 ) - feed_is_expired = b.feed_is_expired_before_hardfork_615( head_time ); - else - feed_is_expired = b.feed_is_expired( head_time ); - if( feed_is_expired ) + const auto& idx = get_index_type().indices().get(); + auto itr = idx.begin(); + while( itr != idx.end() && itr->feed_is_expired( head_time ) ) + { + const asset_bitasset_data_object& b = *itr; + ++itr; // not always process begin() because old code skipped updating some assets before hf 615 + bool update_cer = false; // for better performance, to only update bitasset once, also check CER in this function + const asset_object* asset_ptr = nullptr; + // update feeds, check margin calls + if( after_hardfork_615 || b.feed_is_expired_before_hardfork_615( head_time ) ) { - modify(b, [head_time](asset_bitasset_data_object& a) { - a.update_median_feeds(head_time); - }); - bool called_some = check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); - if( called_some && before_hf_615 ) + auto old_median_feed = b.current_feed; + modify( b, [head_time,&update_cer]( asset_bitasset_data_object& abdo ) { - wlog( "Graphene issue #615: called some for asset ${a} on block #${b}, feed really expired: ${f}", - ("a", a.symbol) ("b", head_num) ("f", b.feed_is_expired(head_time)) ); + abdo.update_median_feeds( head_time ); + if( abdo.need_to_update_cer() ) + { + update_cer = true; + abdo.asset_cer_updated = false; + abdo.feed_cer_updated = false; + } + }); + if( !b.current_feed.settlement_price.is_null() && !( b.current_feed == old_median_feed ) ) // `==` check is safe here + { + asset_ptr = &b.asset_id( *this ); + check_call_orders( *asset_ptr, true, false, &b ); } } - 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; + // update CER + if( update_cer ) + { + if( !asset_ptr ) + asset_ptr = &b.asset_id( *this ); + if( asset_ptr->options.core_exchange_rate != b.current_feed.core_exchange_rate ) + { + modify( *asset_ptr, [&b]( asset_object& ao ) + { + ao.options.core_exchange_rate = b.current_feed.core_exchange_rate; + }); + } + } + } // for each asset whose feed is expired + + // process assets affected by bitshares-core issue 453 before hard fork 615 + if( !after_hardfork_615 ) + { + for( asset_id_type a : _issue_453_affected_assets ) + { + check_call_orders( a(*this) ); + } + } +} + +void database::update_core_exchange_rates() +{ + const auto& idx = get_index_type().indices().get(); + if( idx.begin() != idx.end() ) + { + for( auto itr = idx.rbegin(); itr->need_to_update_cer(); itr = idx.rbegin() ) + { + const asset_bitasset_data_object& b = *itr; + const asset_object& a = b.asset_id( *this ); + if( 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; + }); + } + modify( b, []( asset_bitasset_data_object& abdo ) + { + abdo.asset_cer_updated = false; + abdo.feed_cer_updated = false; }); + } } } diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index f1df4681..cba33bb8 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -193,6 +193,9 @@ namespace graphene { namespace chain { static const uint8_t space_id = implementation_ids; static const uint8_t type_id = impl_asset_bitasset_data_type; + /// The asset this object belong to + asset_id_type asset_id; + /// The tunable options for BitAssets are stored in this field. bitasset_options options; @@ -230,6 +233,18 @@ namespace graphene { namespace chain { share_type settlement_fund; ///@} + /// Track whether core_exchange_rate in corresponding asset_object has updated + bool asset_cer_updated = false; + + /// Track whether core exchange rate in current feed has updated + bool feed_cer_updated = false; + + /// Whether need to update core_exchange_rate in asset_object + bool need_to_update_cer() const + { + return ( ( feed_cer_updated || asset_cer_updated ) && !current_feed.core_exchange_rate.is_null() ); + } + /// The time when @ref current_feed would expire time_point_sec feed_expiration_time()const { @@ -247,14 +262,34 @@ namespace graphene { namespace chain { void update_median_feeds(time_point_sec current_time); }; + // key extractor for short backing asset + struct bitasset_short_backing_asset_extractor + { + typedef asset_id_type result_type; + result_type operator() (const asset_bitasset_data_object& obj) const + { + return obj.options.short_backing_asset; + } + }; + + struct by_short_backing_asset; struct by_feed_expiration; + struct by_cer_update; + typedef multi_index_container< asset_bitasset_data_object, indexed_by< - ordered_unique< tag, member< object, object_id_type, &object::id > >, - ordered_non_unique< tag, - const_mem_fun< asset_bitasset_data_object, time_point_sec, &asset_bitasset_data_object::feed_expiration_time > - > + ordered_unique< tag, member< object, object_id_type, &object::id > >, + ordered_non_unique< tag, bitasset_short_backing_asset_extractor >, + ordered_unique< tag, + composite_key< asset_bitasset_data_object, + const_mem_fun< asset_bitasset_data_object, time_point_sec, &asset_bitasset_data_object::feed_expiration_time >, + member< asset_bitasset_data_object, asset_id_type, &asset_bitasset_data_object::asset_id > + > + >, + ordered_non_unique< tag, + const_mem_fun< asset_bitasset_data_object, bool, &asset_bitasset_data_object::need_to_update_cer > + > > > asset_bitasset_data_object_multi_index_type; //typedef flat_index asset_bitasset_data_index; @@ -481,6 +516,7 @@ FC_REFLECT_DERIVED( graphene::chain::asset_dynamic_data_object, (graphene::db::o (current_supply)(sweeps_tickets_sold)(confidential_supply)(accumulated_fees)(fee_pool) ) FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db::object), + (asset_id) (feeds) (current_feed) (current_feed_publication_time) @@ -489,6 +525,8 @@ FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db:: (is_prediction_market) (settlement_price) (settlement_fund) + (asset_cer_updated) + (feed_cer_updated) ) FC_REFLECT_DERIVED( graphene::chain::asset_dividend_data_object, (graphene::db::object), diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 52cfdd8b..28e84c28 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -437,7 +437,8 @@ namespace graphene { namespace chain { bool fill_order( const call_order_object& order, const asset& pays, const asset& receives ); bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives ); - bool check_call_orders( const asset_object& mia, bool enable_black_swan = true ); + bool check_call_orders( const asset_object& mia, bool enable_black_swan = true, bool for_new_limit_order = false, + const asset_bitasset_data_object* bitasset_ptr = nullptr ); // helpers to fill_order void pay_order( const account_object& receiver, const asset& receives, const asset& pays ); @@ -505,11 +506,13 @@ namespace graphene { namespace chain { void clear_expired_proposals(); void clear_expired_orders(); void update_expired_feeds(); + void update_core_exchange_rates(); void update_maintenance_flag( bool new_maintenance_flag ); void update_withdraw_permissions(); void update_tournaments(); void update_betting_markets(fc::time_point_sec current_block_time); - bool check_for_blackswan( const asset_object& mia, bool enable_black_swan = true ); + bool check_for_blackswan( const asset_object& mia, bool enable_black_swan = true, + const asset_bitasset_data_object* bitasset_ptr = nullptr ); ///Steps performed only at maintenance intervals ///@{ @@ -583,6 +586,8 @@ namespace graphene { namespace chain { * database::close() has not been called, or failed during execution. */ bool _opened = false; + /// Tracks assets affected by bitshares-core issue #453 before hard fork #615 in one block + flat_set _issue_453_affected_assets; }; namespace detail From 04102d549ca1093e4c62d9fad5692981850b73c4 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 3 Jul 2018 18:49:58 -0400 Subject: [PATCH 07/17] Change static refs to member pointers of db class --- libraries/chain/db_getter.cpp | 12 ++++-------- libraries/chain/db_init.cpp | 13 +++++++------ libraries/chain/db_management.cpp | 7 +++++++ libraries/chain/db_market.cpp | 5 +---- libraries/chain/include/graphene/chain/database.hpp | 10 +++++++++- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index c9b20136..3e0a79be 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -37,26 +37,22 @@ namespace graphene { namespace chain { const asset_object& database::get_core_asset() const { - static const asset_object& obj = get(asset_id_type()); - return obj; + return *_p_core_asset_obj; } const global_property_object& database::get_global_properties()const { - static const global_property_object& obj = get( global_property_id_type() ); - return obj; + return *_p_global_prop_obj; } const chain_property_object& database::get_chain_properties()const { - static const chain_property_object& obj = get( chain_property_id_type() ); - return obj; + return *_p_chain_property_obj; } const dynamic_global_property_object& database::get_dynamic_global_properties() const { - static const dynamic_global_property_object& obj = get( dynamic_global_property_id_type() ); - return obj; + return *_p_dyn_global_prop_obj; } const fee_schedule& database::current_fee_schedule()const diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 49d0a69f..f0881cc1 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -493,8 +493,9 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.dynamic_asset_data_id = dyn_asset.id; a.dividend_data_id = div_asset.id; }); - assert( asset_id_type(core_asset.id) == asset().asset_id ); - assert( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) ); + FC_ASSERT( asset_id_type(core_asset.id) == asset().asset_id ); + FC_ASSERT( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) ); + _p_core_asset_obj = &core_asset; #ifdef _DEFAULT_DIVIDEND_ASSET // Create default dividend asset @@ -527,7 +528,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.dynamic_asset_data_id = dyn_asset1.id; a.dividend_data_id = div_asset1.id; }); - assert( default_asset.id == asset_id_type(1) ); + FC_ASSERT( default_asset.id == asset_id_type(1) ); #endif // Create more special assets @@ -560,14 +561,14 @@ void database::init_genesis(const genesis_state_type& genesis_state) chain_id_type chain_id = genesis_state.compute_chain_id(); // Create global properties - create([&](global_property_object& p) { + _p_global_prop_obj = & create([&genesis_state](global_property_object& p) { p.parameters = genesis_state.initial_parameters; // Set fees to zero initially, so that genesis initialization needs not pay them // We'll fix it at the end of the function p.parameters.current_fees->zero_all_fees(); }); - create([&](dynamic_global_property_object& p) { + _p_dyn_global_prop_obj = & create([&genesis_state](dynamic_global_property_object& p) { p.time = genesis_state.initial_timestamp; p.dynamic_flags = 0; p.witness_budget = 0; @@ -580,7 +581,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) FC_ASSERT( (genesis_state.immutable_parameters.min_witness_count & 1) == 1, "min_witness_count must be odd" ); FC_ASSERT( (genesis_state.immutable_parameters.min_committee_member_count & 1) == 1, "min_committee_member_count must be odd" ); - create([&](chain_property_object& p) + _p_chain_property_obj = & create([chain_id,&genesis_state](chain_property_object& p) { p.chain_id = chain_id; p.immutable_parameters = genesis_state.immutable_parameters; diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 029a55d4..b6af0bd3 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -214,6 +214,13 @@ void database::open( if( !find(global_property_id_type()) ) init_genesis(genesis_loader()); + else + { + _p_core_asset_obj = &get( asset_id_type() ); + _p_global_prop_obj = &get( global_property_id_type() ); + _p_chain_property_obj = &get( chain_property_id_type() ); + _p_dyn_global_prop_obj = &get( dynamic_global_property_id_type() ); + } fc::optional last_block = _block_id_to_block.last_id(); if( last_block.valid() ) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index 77acedd3..ad888532 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -429,9 +429,7 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa bool database::check_call_orders( const asset_object& mia, bool enable_black_swan, bool for_new_limit_order, const asset_bitasset_data_object* bitasset_ptr ) { try { - static const auto& dyn_prop = get_dynamic_global_properties(); if( !mia.is_market_issued() ) return false; - auto maint_time = dyn_prop.next_maintenance_time; const asset_bitasset_data_object& bitasset = ( bitasset_ptr ? *bitasset_ptr : mia.bitasset_data(*this) ); @@ -471,7 +469,6 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa auto head_time = head_block_time(); auto head_num = head_block_num(); - bool before_hardfork_615 = ( head_time < HARDFORK_615_TIME ); bool after_hardfork_436 = ( head_time > HARDFORK_436_TIME ); while( !check_for_blackswan( mia, enable_black_swan, &bitasset ) && call_itr != call_end ) @@ -491,7 +488,7 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa // would be margin called, but there is no matching order #436 bool feed_protected = ( bitasset.current_feed.settlement_price > ~call_itr->call_price ); - if( feed_protected && (head_block_time() > HARDFORK_436_TIME) ) + if( feed_protected && after_hardfork_436 ) return margin_called; // would be margin called, but there is no matching order diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 28e84c28..aef0da07 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -447,7 +447,7 @@ namespace graphene { namespace chain { asset pay_market_fees( const asset_object& recv_asset, const asset& receives ); - ///@} + ///@{ /** * This method validates transactions without adding it to the pending state. * @return true if the transaction would validate @@ -588,6 +588,14 @@ namespace graphene { namespace chain { bool _opened = false; /// Tracks assets affected by bitshares-core issue #453 before hard fork #615 in one block flat_set _issue_453_affected_assets; + + /// Pointers to core asset object and global objects who will have immutable addresses after created + ///@{ + const asset_object* _p_core_asset_obj = nullptr; + const global_property_object* _p_global_prop_obj = nullptr; + const dynamic_global_property_object* _p_dyn_global_prop_obj = nullptr; + const chain_property_object* _p_chain_property_obj = nullptr; + ///@} }; namespace detail From dcc69027200fe63a84771c69b107282870710a19 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 5 Jul 2018 13:05:23 -0400 Subject: [PATCH 08/17] Added getter for witness schedule object --- libraries/chain/db_getter.cpp | 4 ++++ libraries/chain/db_init.cpp | 15 +++------------ libraries/chain/db_management.cpp | 1 + libraries/chain/db_witness_schedule.cpp | 12 ++++++------ .../chain/include/graphene/chain/database.hpp | 2 ++ 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 3e0a79be..df7e19ee 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -149,5 +149,9 @@ const account_statistics_object& database::get_account_stats_by_owner( account_i return *itr; } +const witness_schedule_object& database::get_witness_schedule_object()const +{ + return *_p_witness_schedule_obj; +} } } diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index f0881cc1..f995d30a 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -921,7 +921,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); // Set active witnesses - modify(get_global_properties(), [&](global_property_object& p) { + modify(get_global_properties(), [&genesis_state](global_property_object& p) { for( uint32_t i = 1; i <= genesis_state.initial_active_witnesses; ++i ) { p.active_witnesses.insert(witness_id_type(i)); @@ -929,10 +929,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); // Initialize witness schedule -#ifndef NDEBUG - const witness_schedule_object& wso = -#endif - create([&](witness_schedule_object& _wso) + _p_witness_schedule_obj = & create([this](witness_schedule_object& _wso) { // for scheduled memset(_wso.rng_seed.begin(), 0, _wso.rng_seed.size()); @@ -956,19 +953,13 @@ void database::init_genesis(const genesis_state_type& genesis_state) for( const witness_id_type& wid : get_global_properties().active_witnesses ) _wso.current_shuffled_witnesses.push_back( wid ); }); - assert( wso.id == witness_schedule_id_type() ); + FC_ASSERT( _p_witness_schedule_obj->id == witness_schedule_id_type() ); // Enable fees modify(get_global_properties(), [&genesis_state](global_property_object& p) { p.parameters.current_fees = genesis_state.initial_parameters.current_fees; }); - // Create witness scheduler - //create([&]( witness_schedule_object& wso ) - //{ - // for( const witness_id_type& wid : get_global_properties().active_witnesses ) - // wso.current_shuffled_witnesses.push_back( wid ); - //}); // Create FBA counters create([&]( fba_accumulator_object& acc ) diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index b6af0bd3..c79364d7 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -220,6 +220,7 @@ void database::open( _p_global_prop_obj = &get( global_property_id_type() ); _p_chain_property_obj = &get( chain_property_id_type() ); _p_dyn_global_prop_obj = &get( dynamic_global_property_id_type() ); + _p_witness_schedule_obj = &get( witness_schedule_id_type() ); } fc::optional last_block = _block_id_to_block.last_id(); diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index e12c81dc..7a6bb219 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -38,14 +38,14 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) { const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - const witness_schedule_object& wso = witness_schedule_id_type()(*this); + const witness_schedule_object& wso = get_witness_schedule_object();; uint64_t current_aslot = dpo.current_aslot + slot_num; return wso.current_shuffled_witnesses[ current_aslot % wso.current_shuffled_witnesses.size() ]; } if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM && slot_num != 0 ) { - const witness_schedule_object& wso = witness_schedule_id_type()(*this); + const witness_schedule_object& wso = get_witness_schedule_object();; // ask the near scheduler who goes in the given slot bool slot_is_near = wso.scheduler.get_slot(slot_num-1, wid); if(! slot_is_near) @@ -113,7 +113,7 @@ uint32_t database::get_slot_at_time(fc::time_point_sec when)const void database::update_witness_schedule() { - const witness_schedule_object& wso = witness_schedule_id_type()(*this); + const witness_schedule_object& wso = get_witness_schedule_object(); const global_property_object& gpo = get_global_properties(); if( head_block_num() % gpo.active_witnesses.size() == 0 ) @@ -148,7 +148,7 @@ void database::update_witness_schedule() vector database::get_near_witness_schedule()const { - const witness_schedule_object& wso = witness_schedule_id_type()(*this); + const witness_schedule_object& wso = get_witness_schedule_object(); vector result; result.reserve(wso.scheduler.size()); @@ -165,7 +165,7 @@ void database::update_witness_schedule(const signed_block& next_block) { auto start = fc::time_point::now(); const global_property_object& gpo = get_global_properties(); - const witness_schedule_object& wso = get(witness_schedule_id_type()); + const witness_schedule_object& wso = get_witness_schedule_object(); uint32_t schedule_needs_filled = gpo.active_witnesses.size(); uint32_t schedule_slot = get_slot_at_time(next_block.timestamp); @@ -252,7 +252,7 @@ uint32_t database::witness_participation_rate()const } if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) { - const witness_schedule_object& wso = get(witness_schedule_id_type()); + const witness_schedule_object& wso = get_witness_schedule_object(); return uint64_t(GRAPHENE_100_PERCENT) * wso.recent_slots_filled.popcount() / 128; } return 0; diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index aef0da07..b7dcec19 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -280,6 +280,7 @@ namespace graphene { namespace chain { const std::vector get_winner_numbers( asset_id_type for_asset, uint32_t count_members, uint8_t count_winners ) const; std::vector get_seeds( asset_id_type for_asset, uint8_t count_winners )const; uint64_t get_random_bits( uint64_t bound ); + const witness_schedule_object& get_witness_schedule_object()const; time_point_sec head_block_time()const; uint32_t head_block_num()const; @@ -595,6 +596,7 @@ namespace graphene { namespace chain { const global_property_object* _p_global_prop_obj = nullptr; const dynamic_global_property_object* _p_dyn_global_prop_obj = nullptr; const chain_property_object* _p_chain_property_obj = nullptr; + const witness_schedule_object* _p_witness_schedule_obj = nullptr; ///@} }; From 1939cd127b676f247d2532fca885492ce15dad9f Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 5 Jul 2018 13:42:16 -0400 Subject: [PATCH 09/17] Added getter for core dynamic data object --- libraries/chain/db_getter.cpp | 5 +++++ libraries/chain/db_init.cpp | 1 + libraries/chain/db_management.cpp | 1 + libraries/chain/include/graphene/chain/database.hpp | 2 ++ 4 files changed, 9 insertions(+) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index df7e19ee..a6f7af19 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -40,6 +40,11 @@ const asset_object& database::get_core_asset() const return *_p_core_asset_obj; } +const asset_dynamic_data_object& database::get_core_dynamic_data() const +{ + return *_p_core_dynamic_data_obj; +} + const global_property_object& database::get_global_properties()const { return *_p_global_prop_obj; diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index f995d30a..d1b8d073 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -496,6 +496,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) FC_ASSERT( asset_id_type(core_asset.id) == asset().asset_id ); FC_ASSERT( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) ); _p_core_asset_obj = &core_asset; + _p_core_dynamic_data_obj = &dyn_asset; #ifdef _DEFAULT_DIVIDEND_ASSET // Create default dividend asset diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index c79364d7..d586bb0f 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -217,6 +217,7 @@ void database::open( else { _p_core_asset_obj = &get( asset_id_type() ); + _p_core_dynamic_data_obj = &get( asset_dynamic_data_id_type() ); _p_global_prop_obj = &get( global_property_id_type() ); _p_chain_property_obj = &get( chain_property_id_type() ); _p_dyn_global_prop_obj = &get( dynamic_global_property_id_type() ); diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index b7dcec19..2039d7ce 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -271,6 +271,7 @@ namespace graphene { namespace chain { const chain_id_type& get_chain_id()const; const asset_object& get_core_asset()const; + const asset_dynamic_data_object& get_core_dynamic_data()const; const chain_property_object& get_chain_properties()const; const global_property_object& get_global_properties()const; const dynamic_global_property_object& get_dynamic_global_properties()const; @@ -593,6 +594,7 @@ namespace graphene { namespace chain { /// Pointers to core asset object and global objects who will have immutable addresses after created ///@{ const asset_object* _p_core_asset_obj = nullptr; + const asset_dynamic_data_object* _p_core_dynamic_data_obj = nullptr; const global_property_object* _p_global_prop_obj = nullptr; const dynamic_global_property_object* _p_dyn_global_prop_obj = nullptr; const chain_property_object* _p_chain_property_obj = nullptr; From 83736ba6562322c04fcf33d42a9063fa265ff23f Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 5 Jul 2018 13:52:55 -0400 Subject: [PATCH 10/17] Use getters --- libraries/chain/account_object.cpp | 8 ++++---- libraries/chain/db_balance.cpp | 2 +- libraries/chain/db_maint.cpp | 11 +++++------ libraries/chain/db_update.cpp | 2 +- libraries/chain/worker_evaluator.cpp | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index c25abdd8..466f7a6f 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -59,8 +59,8 @@ void account_statistics_object::process_fees(const account_object& a, database& // Check the referrer -- if he's no longer a member, pay to the lifetime referrer instead. // No need to check the registrar; registrars are required to be lifetime members. if( account.referrer(d).is_basic_account(d.head_block_time()) ) - d.modify(account, [](account_object& a) { - a.referrer = a.lifetime_referrer; + d.modify( account, [](account_object& acc) { + acc.referrer = acc.lifetime_referrer; }); share_type network_cut = cut_fee(core_fee_total, account.network_fee_percentage); @@ -76,8 +76,8 @@ void account_statistics_object::process_fees(const account_object& a, database& share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage); share_type referral = core_fee_total - network_cut - lifetime_cut; - d.modify(asset_dynamic_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) { - d.accumulated_fees += network_cut; + d.modify( d.get_core_dynamic_data(), [network_cut](asset_dynamic_data_object& addo) { + addo.accumulated_fees += network_cut; }); // Potential optimization: Skip some of this math and object lookups by special casing on the account type. diff --git a/libraries/chain/db_balance.cpp b/libraries/chain/db_balance.cpp index 5029d3b7..55729050 100644 --- a/libraries/chain/db_balance.cpp +++ b/libraries/chain/db_balance.cpp @@ -210,7 +210,7 @@ void database::deposit_cashback(const account_object& acct, share_type amount, b acct.get_id() == GRAPHENE_TEMP_ACCOUNT ) { // The blockchain's accounts do not get cashback; it simply goes to the reserve pool. - modify(get(asset_id_type()).dynamic_asset_data_id(*this), [amount](asset_dynamic_data_object& d) { + modify( get_core_dynamic_data(), [amount](asset_dynamic_data_object& d) { d.current_supply -= amount; }); return; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 2b386633..10bc0ac3 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -398,8 +398,8 @@ void database::update_active_committee_members() void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const { const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - const asset_object& core = asset_id_type(0)(*this); - const asset_dynamic_data_object& core_dd = core.dynamic_asset_data_id(*this); + const asset_object& core = get_core_asset(); + const asset_dynamic_data_object& core_dd = get_core_dynamic_data(); rec.from_initial_reserve = core.reserved(*this); rec.from_accumulated_fees = core_dd.accumulated_fees; @@ -452,8 +452,7 @@ void database::process_budget() { const global_property_object& gpo = get_global_properties(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - const asset_dynamic_data_object& core = - asset_id_type(0)(*this).dynamic_asset_data_id(*this); + const asset_dynamic_data_object& core = get_core_dynamic_data(); fc::time_point_sec now = head_block_time(); int64_t time_to_maint = (dpo.next_maintenance_time - now).to_seconds(); @@ -613,8 +612,8 @@ void split_fba_balance( if( fba.accumulated_fba_fees == 0 ) return; - const asset_object& core = asset_id_type(0)(db); - const asset_dynamic_data_object& core_dd = core.dynamic_asset_data_id(db); + const asset_object& core = db.get_core_asset(); + const asset_dynamic_data_object& core_dd = db.get_core_dynamic_data(); if( !fba.is_configured(db) ) { diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index eb4acd0d..5c0fbfc9 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -45,7 +45,7 @@ namespace graphene { namespace chain { void database::update_global_dynamic_data( const signed_block& b, const uint32_t missed_blocks ) { - const dynamic_global_property_object& _dgp = dynamic_global_property_id_type(0)(*this); + const dynamic_global_property_object& _dgp = get_dynamic_global_properties(); const global_property_object& gpo = get_global_properties(); // dynamic global properties updating diff --git a/libraries/chain/worker_evaluator.cpp b/libraries/chain/worker_evaluator.cpp index cf6f0e00..b5aea8f3 100644 --- a/libraries/chain/worker_evaluator.cpp +++ b/libraries/chain/worker_evaluator.cpp @@ -106,7 +106,7 @@ object_id_type worker_create_evaluator::do_apply(const worker_create_evaluator:: void refund_worker_type::pay_worker(share_type pay, database& db) { total_burned += pay; - db.modify(db.get(asset_id_type()).dynamic_data(db), [pay](asset_dynamic_data_object& d) { + db.modify( db.get_core_dynamic_data(), [pay](asset_dynamic_data_object& d) { d.current_supply -= pay; }); } From 66f6f269342ab0bdb2e713f624777956224d8d86 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 5 Jul 2018 14:15:18 -0400 Subject: [PATCH 11/17] Removed unused variable --- libraries/chain/db_maint.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 10bc0ac3..072c05a0 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -612,7 +612,6 @@ void split_fba_balance( if( fba.accumulated_fba_fees == 0 ) return; - const asset_object& core = db.get_core_asset(); const asset_dynamic_data_object& core_dd = db.get_core_dynamic_data(); if( !fba.is_configured(db) ) From 2f6de1f0561ab3be8e5b718e09928626d390fa1d Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 25 Jul 2018 15:32:41 -0400 Subject: [PATCH 12/17] Add comments for update_expired_feeds in db_block --- libraries/chain/db_block.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 45d75fa5..5174e018 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -640,8 +640,8 @@ void database::_apply_block( const signed_block& next_block ) clear_expired_transactions(); clear_expired_proposals(); clear_expired_orders(); - update_expired_feeds(); - update_core_exchange_rates(); + update_expired_feeds(); // this will update expired feeds and some core exchange rates + update_core_exchange_rates(); // this will update remaining core exchange rates update_withdraw_permissions(); update_tournaments(); update_betting_markets(next_block.timestamp); From 02f6019896c9bff5e680ba2648b557e7969519cd Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 26 Jul 2018 05:08:31 -0400 Subject: [PATCH 13/17] Minor refactory asset_create_evaluator::do_apply() --- libraries/chain/asset_evaluator.cpp | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 21378ce1..7a26a2cb 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -133,34 +133,36 @@ void asset_create_evaluator::pay_fee() object_id_type asset_create_evaluator::do_apply( const asset_create_operation& op ) { try { + database& d = db(); + // includes changes from bitshares. (https://github.com/bitshares/bitshares-core/issues/429) bool hf_429 = fee_is_odd && db().head_block_time() > HARDFORK_CORE_429_TIME; const asset_dynamic_data_object& dyn_asset = - db().create( [hf_429,this]( asset_dynamic_data_object& a ) { + d.create( [hf_429,this]( asset_dynamic_data_object& a ) { a.current_supply = 0; a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0); }); if( fee_is_odd && !hf_429 ) { - const auto& core_dd = db().get_core_asset().dynamic_data( db() ); - db().modify( core_dd, []( asset_dynamic_data_object& dd ) { + const auto& core_dd = d.get_core_asset().dynamic_data( d ); + d.modify( core_dd, []( asset_dynamic_data_object& dd ) { dd.current_supply++; }); } - auto next_asset_id = db().get_index_type().get_next_id(); + auto next_asset_id = d.get_index_type().get_next_id(); asset_bitasset_data_id_type bit_asset_id; if( op.bitasset_opts.valid() ) - bit_asset_id = db().create( [&]( asset_bitasset_data_object& a ) { + bit_asset_id = d.create( [&]( asset_bitasset_data_object& a ) { a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; a.asset_id = next_asset_id; }).id; const asset_object& new_asset = - db().create( [&]( asset_object& a ) { + d.create( [&]( asset_object& a ) { a.issuer = op.issuer; a.symbol = op.symbol; a.precision = op.precision; @@ -176,7 +178,7 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o if( op.bitasset_opts.valid() ) a.bitasset_data_id = bit_asset_id; }); - assert( new_asset.id == next_asset_id ); + FC_ASSERT( new_asset.id == next_asset_id ); return new_asset.id; } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -282,34 +284,36 @@ void lottery_asset_create_evaluator::pay_fee() object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_create_operation& op ) { try { + database& d = db(); + // includes changes from bitshares. (https://github.com/bitshares/bitshares-core/issues/429) - bool hf_429 = fee_is_odd && db().head_block_time() > HARDFORK_CORE_429_TIME; + bool hf_429 = fee_is_odd && d.head_block_time() > HARDFORK_CORE_429_TIME; const asset_dynamic_data_object& dyn_asset = - db().create( [&]( asset_dynamic_data_object& a ) { + d.create( [&]( asset_dynamic_data_object& a ) { a.current_supply = 0; a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0); }); if( fee_is_odd && !hf_429 ) { - const auto& core_dd = db().get( asset_id_type() ).dynamic_data( db() ); - db().modify( core_dd, [=]( asset_dynamic_data_object& dd ) { + const auto& core_dd = d.get( asset_id_type() ).dynamic_data( db() ); + d.modify( core_dd, [=]( asset_dynamic_data_object& dd ) { dd.current_supply++; }); } - auto next_asset_id = db().get_index_type().get_next_id(); + auto next_asset_id = d.get_index_type().get_next_id(); asset_bitasset_data_id_type bit_asset_id; if( op.bitasset_opts.valid() ) - bit_asset_id = db().create( [&op,next_asset_id]( asset_bitasset_data_object& a ) { + bit_asset_id = d.create( [&op,next_asset_id]( asset_bitasset_data_object& a ) { a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; a.asset_id = next_asset_id; }).id; const asset_object& new_asset = - db().create( [&op,next_asset_id,&dyn_asset,bit_asset_id,this]( asset_object& a ) { + d.create( [&op,next_asset_id,&dyn_asset,bit_asset_id,&d]( asset_object& a ) { a.issuer = op.issuer; a.symbol = op.symbol; a.precision = op.precision; @@ -318,7 +322,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre a.lottery_options = op.extensions; //a.lottery_options->balance = asset( 0, a.lottery_options->ticket_price.asset_id ); a.lottery_options->owner = a.id; - db().create([&](lottery_balance_object& lbo) { + d.create([&a](lottery_balance_object& lbo) { lbo.lottery_id = a.id; }); if( a.options.core_exchange_rate.base.asset_id.instance.value == 0 ) @@ -329,7 +333,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre if( op.bitasset_opts.valid() ) a.bitasset_data_id = bit_asset_id; }); - FC_ASSERT( new_asset.id == next_asset_id ); + FC_ASSERT( new_asset.id == next_asset_id, "Unexpected object database error, object id mismatch" ); return new_asset.id; } FC_CAPTURE_AND_RETHROW( (op) ) } From 6a7d670762d6b51fba62290529d3a279f61800b7 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 26 Jul 2018 05:49:45 -0400 Subject: [PATCH 14/17] Added FC_ASSERT for dynamic data id of core asset --- libraries/chain/db_init.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index d1b8d073..4e30029b 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -492,7 +492,8 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.options.core_exchange_rate.quote.asset_id = asset_id_type(0); a.dynamic_asset_data_id = dyn_asset.id; a.dividend_data_id = div_asset.id; - }); + }); + FC_ASSERT( dyn_asset.id == asset_dynamic_data_id_type() ); FC_ASSERT( asset_id_type(core_asset.id) == asset().asset_id ); FC_ASSERT( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) ); _p_core_asset_obj = &core_asset; From 4f54b13074def8dd3b0812b0ab89cacd374d78bd Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 26 Jul 2018 12:53:55 -0400 Subject: [PATCH 15/17] Added header inclusions in db_management.cpp --- libraries/chain/db_management.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index d586bb0f..4fcbc01e 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -24,6 +24,9 @@ #include +#include +#include +#include #include #include From d99ef0c1f9b5696e8872466678895ee334d561cc Mon Sep 17 00:00:00 2001 From: gladcow Date: Thu, 5 Sep 2019 09:40:17 +0300 Subject: [PATCH 16/17] fix global objects usage during replay --- libraries/chain/db_management.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 4fcbc01e..c6380b8c 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -179,7 +179,7 @@ void database::wipe(const fc::path& data_dir, bool include_blocks) { ilog("Wiping database", ("include_blocks", include_blocks)); if (_opened) { - close(); + close(false); } object_database::wipe(data_dir); if( include_blocks ) From d3b2c4ce9576525f739af0725bc40e2d6b59747c Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 26 Jul 2018 05:25:54 -0400 Subject: [PATCH 17/17] Simplified code in database::pay_workers() --- libraries/chain/db_maint.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 072c05a0..0d7bb405 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -173,21 +173,20 @@ void database::pay_workers( share_type& budget ) const auto last_budget_time = get_dynamic_global_properties().last_budget_time; const auto passed_time_ms = head_time - last_budget_time; - const bool passed_time_is_a_day = ( passed_time_ms == fc::days(1) ); - // the variable above is more likely false on BitShares mainnet, so do calculations below anyway const auto passed_time_count = passed_time_ms.count(); const auto day_count = fc::days(1).count(); for( uint32_t i = 0; i < active_workers.size() && budget > 0; ++i ) { const worker_object& active_worker = active_workers[i]; share_type requested_pay = active_worker.daily_pay; - if( !passed_time_is_a_day ) - { - fc::uint128 pay(requested_pay.value); - pay *= passed_time_count; - pay /= day_count; - requested_pay = pay.to_uint64(); - } + + // Note: if there is a good chance that passed_time_count == day_count, + // for better performance, can avoid the 128 bit calculation by adding a check. + // Since it's not the case on BitShares mainnet, we're not using a check here. + fc::uint128 pay(requested_pay.value); + pay *= passed_time_count; + pay /= day_count; + requested_pay = pay.to_uint64(); share_type actual_pay = std::min(budget, requested_pay); //ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));