From e3f5e2cf8d3a487e8538c0c52fd294123cb2bbb7 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 30 Jun 2015 11:59:53 -0400 Subject: [PATCH] Resolve #104: Set minimum feeds on bitassets --- libraries/chain/asset_evaluator.cpp | 10 +++++- libraries/chain/asset_object.cpp | 5 ++- .../include/graphene/chain/asset_object.hpp | 3 ++ tests/tests/operation_tests2.cpp | 31 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index f6f62629..1e90b116 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -299,8 +299,16 @@ void_result asset_update_bitasset_evaluator::do_evaluate(const asset_update_bita void_result asset_update_bitasset_evaluator::do_apply(const asset_update_bitasset_operation& o) { try { - db().modify(*bitasset_to_update, [&o](asset_bitasset_data_object& b) { + bool should_update_feeds = false; + // If the minimum number of feeds to calculate a median has changed, we need to recalculate the median + if( o.new_options.minimum_feeds != bitasset_to_update->options.minimum_feeds ) + should_update_feeds = true; + + db().modify(*bitasset_to_update, [&](asset_bitasset_data_object& b) { b.options = o.new_options; + + if( should_update_feeds ) + b.update_median_feeds(db().head_block_time()); }); return void_result(); diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index db855d9f..3f94479a 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -52,8 +52,10 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point } } - if( current_feeds.empty() ) + // If there are no valid feeds, or the number available is less than the minimum to calculate a median... + if( current_feeds.size() < options.minimum_feeds ) { + //... don't calculate a median, and set a null feed current_feed_publication_time = current_time; current_feed = price_feed(); return; @@ -111,6 +113,7 @@ void asset_object::asset_options::validate()const void asset_object::bitasset_options::validate() const { + FC_ASSERT(minimum_feeds > 0); FC_ASSERT(force_settlement_offset_percent <= GRAPHENE_100_PERCENT); FC_ASSERT(maximum_force_settlement_volume <= GRAPHENE_100_PERCENT); } diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index ce15b0ba..9f902d0b 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -174,6 +174,8 @@ namespace graphene { namespace chain { struct bitasset_options { /// Time before a price feed expires uint32_t feed_lifetime_sec = GRAPHENE_DEFAULT_PRICE_FEED_LIFETIME; + /// Minimum number of unexpired feeds required to extract a median feed from + uint8_t minimum_feeds = 1; /// This is the delay between the time a long requests settlement and the chain evaluates the settlement uint32_t force_settlement_delay_sec = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY; /// This is the percent to adjust the feed price in the short's favor in the event of a forced settlement @@ -332,6 +334,7 @@ FC_REFLECT( graphene::chain::asset_object::asset_options, ) FC_REFLECT( graphene::chain::asset_object::bitasset_options, (feed_lifetime_sec) + (minimum_feeds) (force_settlement_delay_sec) (force_settlement_offset_percent) (maximum_force_settlement_volume) diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 66e2ce57..4fb6b9bd 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -373,6 +373,37 @@ BOOST_AUTO_TEST_CASE( mia_feeds ) } } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( feed_limit_test ) +{ try { + INVOKE( mia_feeds ); + const asset_object& bit_usd = get_asset("BITUSD"); + const asset_bitasset_data_object& bitasset = bit_usd.bitasset_data(db); + GET_ACTOR(nathan); + + BOOST_CHECK(!bitasset.current_feed.settlement_price.is_null()); + + BOOST_TEST_MESSAGE("Setting minimum feeds to 4"); + asset_update_bitasset_operation op; + op.new_options.minimum_feeds = 4; + op.asset_to_update = bit_usd.get_id(); + op.issuer = bit_usd.issuer; + trx.operations = {op}; + trx.sign(nathan_key_id, nathan_private_key); + db.push_transaction(trx); + + BOOST_TEST_MESSAGE("Checking current_feed is null"); + BOOST_CHECK(bitasset.current_feed.settlement_price.is_null()); + + BOOST_TEST_MESSAGE("Setting minimum feeds to 3"); + op.new_options.minimum_feeds = 3; + trx.operations = {op}; + trx.sign(nathan_key_id, nathan_private_key); + db.push_transaction(trx); + + BOOST_TEST_MESSAGE("Checking current_feed is not null"); + BOOST_CHECK(!bitasset.current_feed.settlement_price.is_null()); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE( witness_create ) { try { ACTOR(nathan);