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 all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
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 true does not always mean a black
// 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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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