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 1 commit
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
4 changes: 4 additions & 0 deletions libraries/chain/db_market.cpp
Expand Up @@ -1003,6 +1003,10 @@ 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) );

// previously, price feeds could cause black swan in prediction market
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
64 changes: 64 additions & 0 deletions tests/tests/operation_tests.cpp
Expand Up @@ -840,6 +840,70 @@ 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);

// interestingly, PMARKII cannot be created without dan force_settling
force_settle( dan, pmark.amount(1000) );
pmconrad marked this conversation as resolved.
Show resolved Hide resolved

// progress past hardfork
generate_blocks( HARDFORK_CORE_460_TIME );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
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