Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent black swan in prediction markets #2019

Merged
merged 5 commits into from Oct 11, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions libraries/chain/db_market.cpp
Expand Up @@ -1003,6 +1003,14 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
if( !mia.is_market_issued() ) return false;

const asset_bitasset_data_object& bitasset = ( bitasset_ptr ? *bitasset_ptr : mia.bitasset_data(*this) );

// price feeds can cause black swans in prediction markets
// The hardfork check may be able to be removed after the hardfork date
// if check_for_blackswan never triggered a black swan on a prediction market.
// NOTE: check_for_blackswan returning false does not always mean a black
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
// swan was triggered.
if ( maint_time >= HARDFORK_CORE_460_TIME && bitasset.is_prediction_market )
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
return false;

if( check_for_blackswan( mia, enable_black_swan, &bitasset ) )
return false;
Expand Down
4 changes: 4 additions & 0 deletions libraries/chain/hardfork.d/CORE_460.hf
@@ -0,0 +1,4 @@
// bitshares-core issue #460 Prediction Market price feed should not cause black swan
#ifndef HARDFORK_CORE_460_TIME
#define HARDFORK_CORE_460_TIME (fc::time_point_sec( 1609372800 ) ) // 2020-12-31T00:00:00
#endif
62 changes: 62 additions & 0 deletions tests/tests/operation_tests.cpp
Expand Up @@ -840,6 +840,68 @@ BOOST_AUTO_TEST_CASE( prediction_market_resolves_to_0 )
}
}

/***
* Prediction markets should not suffer a black swan (Issue #460)
*/
BOOST_AUTO_TEST_CASE( prediction_market_black_swan )
{
try {
ACTORS((judge)(dan)(nathan));

// progress to recent hardfork
generate_blocks( HARDFORK_CORE_1270_TIME );
set_expiration( db, trx );

const auto& pmark = create_prediction_market("PMARK", judge_id);

int64_t init_balance(1000000);
transfer(committee_account, judge_id, asset(init_balance));
transfer(committee_account, dan_id, asset(init_balance));

update_feed_producers( pmark, { judge_id });
price_feed feed;
feed.settlement_price = asset( 1, pmark.id ) / asset( 1 );
publish_feed( pmark, judge, feed );

borrow( dan, pmark.amount(1000), asset(1000) );

// feed a price that will cause a black swan
feed.settlement_price = asset( 1, pmark.id ) / asset( 1000 );
publish_feed( pmark, judge, feed );

// verify a black swan happened
GRAPHENE_REQUIRE_THROW(borrow( dan, pmark.amount(1000), asset(1000) ), fc::exception);
trx.clear();

// progress past hardfork
generate_blocks( HARDFORK_CORE_460_TIME + db.get_global_properties().parameters.maintenance_interval );
set_expiration( db, trx );

// create another prediction market to test the hardfork
const auto& pmark2 = create_prediction_market("PMARKII", judge_id);
update_feed_producers( pmark2, { judge_id });
price_feed feed2;
feed2.settlement_price = asset( 1, pmark2.id ) / asset( 1 );
publish_feed( pmark2, judge, feed2 );

borrow( dan, pmark2.amount(1000), asset(1000) );

// feed a price that would have caused a black swan
feed2.settlement_price = asset( 1, pmark2.id ) / asset( 1000 );
publish_feed( pmark2, judge, feed2 );

// verify a black swan did not happen
borrow( dan, pmark2.amount(1000), asset(1000) );

generate_block(~database::skip_transaction_dupe_check);
generate_blocks( db.get_dynamic_global_properties().next_maintenance_time );
generate_block();
} catch( const fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}

BOOST_AUTO_TEST_CASE( create_account_test )
{
try {
Expand Down