From 5b55ab71eac48f1a4fb52b883f72a168d7a5a387 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Fri, 26 Jun 2015 10:42:40 -0400 Subject: [PATCH] Resolve #94 Core exchange rate is now redundantly stored in price feed for bitassets, and updated when the median feed changes. This allows feed producers to update the core exchange rate. Redundant storage is necessary, because the core exchange rate is needed for user-issued assets as well as market issued assets. --- libraries/chain/asset_evaluator.cpp | 10 ++++++++-- libraries/chain/db_update.cpp | 20 +++++++++++++------ .../chain/include/graphene/chain/asset.hpp | 16 +++++++++------ tests/common/database_fixture.cpp | 2 +- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index a06f0e6d..536450cd 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -58,7 +58,7 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o FC_ASSERT( op.bitasset_options->feed_lifetime_sec > chain_parameters.block_interval && op.bitasset_options->force_settlement_delay_sec > chain_parameters.block_interval ); } - if( op.is_prediction_market ) + if( op.is_prediction_market ) { FC_ASSERT( op.bitasset_options ); FC_ASSERT( op.precision == op.bitasset_options->short_backing_asset(d).precision ); @@ -313,6 +313,9 @@ void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_f a.feeds[*itr]; a.update_median_feeds(db().head_block_time()); }); + db().modify(o.asset_to_update(db()), [this](asset_object& a) { + a.options.core_exchange_rate = bitasset_to_update->current_feed.core_exchange_rate; + }); db().check_call_orders( o.asset_to_update(db()) ); return void_result(); @@ -429,9 +432,12 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed); a.update_median_feeds(d.head_block_time()); }); + d.modify(base, [&d](asset_object& a) { + a.options.core_exchange_rate = a.bitasset_data(d).current_feed.core_exchange_rate; + }); /// TODO: optimization: only do this if the median feed actually changed, otherwise there is no point - db().check_call_orders( base ); + db().check_call_orders(base); return void_result(); } FC_CAPTURE_AND_RETHROW((o)) } diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 8890313d..51353ed8 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -219,16 +219,24 @@ void database::clear_expired_orders() void database::update_expired_feeds() { - auto& asset_idx = get_index_type(); - for( const asset_bitasset_data_object* b : asset_idx ) - if( b->feed_is_expired(head_block_time()) ) + auto& asset_idx = get_index_type().indices(); + for( const asset_object& a : asset_idx ) + { + if( !a.is_market_issued() ) + continue; + + const asset_bitasset_data_object& b = a.bitasset_data(*this); + if( b.feed_is_expired(head_block_time()) ) { - modify(*b, [this](asset_bitasset_data_object& a) { + modify(b, [this](asset_bitasset_data_object& a) { a.update_median_feeds(head_block_time()); }); - - check_call_orders( b->current_feed.settlement_price.base.asset_id(*this) ); + modify(a, [&b](asset_object& a) { + a.options.core_exchange_rate = b.current_feed.core_exchange_rate; + }); + check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); } + } } void database::update_withdraw_permissions() diff --git a/libraries/chain/include/graphene/chain/asset.hpp b/libraries/chain/include/graphene/chain/asset.hpp index 697099a8..af9d1719 100644 --- a/libraries/chain/include/graphene/chain/asset.hpp +++ b/libraries/chain/include/graphene/chain/asset.hpp @@ -141,10 +141,13 @@ namespace graphene { namespace chain { */ ///@{ /** - * Forced settlements will evaluate using this price, defined as BITASSET / COLLATERAL + * Forced settlements will evaluate using this price, defined as BITASSET / COLLATERAL */ price settlement_price; + /// Price at which automatically exchanging this asset for CORE from fee pool occurs (used for paying fees) + price core_exchange_rate; + /** Fixed point between 1.000 and 10.000, implied fixed point denominator is GRAPHENE_COLLATERAL_RATIO_DENOM */ uint16_t maintenance_collateral_ratio = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO; @@ -154,14 +157,14 @@ namespace graphene { namespace chain { /** * When updating a call order the following condition must be maintained: * - * debt * maintenance_price() < collateral + * debt * maintenance_price() < collateral * debt * settlement_price < debt * maintenance - * debt * maintenance_price() < debt * max_short_squeeze_price() + * debt * maintenance_price() < debt * max_short_squeeze_price() price maintenance_price()const; */ - /** When selling collateral to pay off debt, the least amount of debt to receive should be - * min_usd = max_short_squeeze_price() * collateral + /** When selling collateral to pay off debt, the least amount of debt to receive should be + * min_usd = max_short_squeeze_price() * collateral * * This is provided to ensure that a black swan cannot be trigged due to poor liquidity alone, it * must be confirmed by having the max_short_squeeze_price() move below the black swan price. @@ -183,7 +186,8 @@ namespace graphene { namespace chain { FC_REFLECT( graphene::chain::asset, (amount)(asset_id) ) FC_REFLECT( graphene::chain::price, (base)(quote) ) -#define GRAPHENE_PRICE_FEED_FIELDS (settlement_price)(maintenance_collateral_ratio)(maximum_short_squeeze_ratio) +#define GRAPHENE_PRICE_FEED_FIELDS (settlement_price)(maintenance_collateral_ratio)(maximum_short_squeeze_ratio) \ + (core_exchange_rate) FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS ) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 84c45313..458a242a 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -400,7 +400,7 @@ const asset_object& database_fixture::create_bitasset( creator.fee = asset(); creator.symbol = name; creator.common_options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; - creator.precision = 2; + creator.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; creator.common_options.market_fee_percent = market_fee_percent; creator.common_options.issuer_permissions = flags; creator.common_options.flags = flags & ~global_settle;