operation_tests2.cpp: Implement force_settlement_test

This commit is contained in:
theoreticalbts 2015-07-20 12:55:58 -04:00
parent cb2031a1e4
commit 5f12f3f445
3 changed files with 187 additions and 122 deletions

View file

@ -740,7 +740,7 @@ void database_fixture::force_global_settle( const asset_object& what, const pric
verify_asset_supplies(db);
} FC_CAPTURE_AND_RETHROW( (what)(p) ) }
void database_fixture::force_settle( const account_object& who, asset what )
operation_result database_fixture::force_settle( const account_object& who, asset what )
{ try {
trx.set_expiration(db.head_block_time() + fc::minutes(1));
trx.operations.clear();
@ -750,9 +750,11 @@ void database_fixture::force_settle( const account_object& who, asset what )
trx.operations.push_back(sop);
for( auto& op : trx.operations ) db.current_fee_schedule().set_fee(op);
trx.validate();
db.push_transaction(trx, ~0);
processed_transaction ptx = db.push_transaction(trx, ~0);
const operation_result& op_result = ptx.operation_results.front();
trx.operations.clear();
verify_asset_supplies(db);
return op_result;
} FC_CAPTURE_AND_RETHROW( (who)(what) ) }
const call_order_object* database_fixture::borrow(const account_object& who, asset what, asset collateral)

View file

@ -190,9 +190,9 @@ struct database_fixture {
);
void force_global_settle(const asset_object& what, const price& p);
void force_settle(account_id_type who, asset what)
{ force_settle(who(db), what); }
void force_settle(const account_object& who, asset what);
operation_result force_settle(account_id_type who, asset what)
{ return force_settle(who(db), what); }
operation_result force_settle(const account_object& who, asset what);
void update_feed_producers(asset_id_type mia, flat_set<account_id_type> producers)
{ update_feed_producers(mia(db), producers); }
void update_feed_producers(const asset_object& mia, flat_set<account_id_type> producers);

View file

@ -820,128 +820,191 @@ BOOST_AUTO_TEST_CASE( burn_worker_test )
BOOST_CHECK_EQUAL( get_balance(GRAPHENE_NULL_ACCOUNT, asset_id_type()), 2000 );
}FC_LOG_AND_RETHROW()}
BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES( unimp_force_settlement_unavailable, 1 )
BOOST_AUTO_TEST_CASE( unimp_force_settlement_unavailable )
BOOST_AUTO_TEST_CASE( force_settle_test )
{
BOOST_FAIL( "TODO - Reimplement this" );
/*
try {
auto private_key = init_account_priv_key;
auto private_key = generate_private_key("committee");
>>>>>>> short_refactor
account_id_type nathan_id = create_account("nathan").get_id();
account_id_type shorter1_id = create_account("shorter1").get_id();
account_id_type shorter2_id = create_account("shorter2").get_id();
account_id_type shorter3_id = create_account("shorter3").get_id();
transfer(account_id_type()(db), nathan_id(db), asset(100000000));
transfer(account_id_type()(db), shorter1_id(db), asset(100000000));
transfer(account_id_type()(db), shorter2_id(db), asset(100000000));
transfer(account_id_type()(db), shorter3_id(db), asset(100000000));
asset_id_type bit_usd = create_bitasset("BITUSD", GRAPHENE_TEMP_ACCOUNT, 0, disable_force_settle).get_id();
FC_ASSERT( bit_usd(db).is_market_issued() );
try
{
asset_update_bitasset_operation op;
op.asset_to_update = bit_usd;
op.issuer = bit_usd(db).issuer;
op.new_options = bit_usd(db).bitasset_data(db).options;
op.new_options.maximum_force_settlement_volume = 9000;
trx.clear();
trx.operations.push_back(op);
PUSH_TX( db, trx, ~0 );
trx.clear();
ACTORS( (nathan)(shorter1)(shorter2)(shorter3)(shorter4)(shorter5) );
int64_t initial_balance = 100000000;
transfer(account_id_type()(db), shorter1_id(db), asset(initial_balance));
transfer(account_id_type()(db), shorter2_id(db), asset(initial_balance));
transfer(account_id_type()(db), shorter3_id(db), asset(initial_balance));
transfer(account_id_type()(db), shorter4_id(db), asset(initial_balance));
transfer(account_id_type()(db), shorter5_id(db), asset(initial_balance));
asset_id_type bitusd_id = create_bitasset(
"BITUSD",
nathan_id,
100,
disable_force_settle
).id;
asset_id_type core_id = asset_id_type();
auto update_bitasset_options = [&]( asset_id_type asset_id,
std::function< void(bitasset_options&) > update_function )
{
const asset_object& _asset = asset_id(db);
asset_update_bitasset_operation op;
op.asset_to_update = asset_id;
op.issuer = _asset.issuer;
op.new_options = (*_asset.bitasset_data_id)(db).options;
update_function( op.new_options );
signed_transaction tx;
tx.operations.push_back( op );
tx.set_expiration( db.head_block_time() + fc::minutes(5) );
PUSH_TX( db, tx, ~0 );
} ;
auto update_asset_options = [&]( asset_id_type asset_id,
std::function< void(asset_options&) > update_function )
{
const asset_object& _asset = asset_id(db);
asset_update_operation op;
op.asset_to_update = asset_id;
op.issuer = _asset.issuer;
op.new_options = _asset.options;
update_function( op.new_options );
signed_transaction tx;
tx.operations.push_back( op );
tx.set_expiration( db.head_block_time() + fc::minutes(5) );
PUSH_TX( db, tx, ~0 );
} ;
BOOST_TEST_MESSAGE( "Update maximum_force_settlement_volume = 9000" );
BOOST_CHECK( bitusd_id(db).is_market_issued() );
update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
{ new_options.maximum_force_settlement_volume = 9000; } );
BOOST_TEST_MESSAGE( "Publish price feed" );
update_feed_producers( bitusd_id, { nathan_id } );
{
price_feed feed;
feed.settlement_price = price( asset( 1, bitusd_id ), asset( 1, core_id ) );
publish_feed( bitusd_id, nathan_id, feed );
}
BOOST_TEST_MESSAGE( "First short batch" );
call_order_id_type call1_id = borrow( shorter1_id, asset(1000, bitusd_id), asset(2*1000, core_id) )->id; // 2.0000
call_order_id_type call2_id = borrow( shorter2_id, asset(2000, bitusd_id), asset(2*1999, core_id) )->id; // 1.9990
call_order_id_type call3_id = borrow( shorter3_id, asset(3000, bitusd_id), asset(2*2890, core_id) )->id; // 1.9267
call_order_id_type call4_id = borrow( shorter4_id, asset(4000, bitusd_id), asset(2*3950, core_id) )->id; // 1.9750
call_order_id_type call5_id = borrow( shorter5_id, asset(5000, bitusd_id), asset(2*4900, core_id) )->id; // 1.9600
transfer( shorter1_id, nathan_id, asset(1000, bitusd_id) );
transfer( shorter2_id, nathan_id, asset(2000, bitusd_id) );
transfer( shorter3_id, nathan_id, asset(3000, bitusd_id) );
transfer( shorter4_id, nathan_id, asset(4000, bitusd_id) );
transfer( shorter5_id, nathan_id, asset(5000, bitusd_id) );
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 15000);
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 0);
BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2000 );
BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-3998 );
BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-5780 );
BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-7900 );
BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-9800 );
BOOST_TEST_MESSAGE( "Update force_settlement_delay_sec = 100, force_settlement_offset_percent = 1%" );
update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
{ new_options.force_settlement_delay_sec = 100;
new_options.force_settlement_offset_percent = GRAPHENE_1_PERCENT; } );
// Force settlement is disabled; check that it fails
GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 50, bitusd_id ) ), fc::exception );
update_asset_options( bitusd_id, [&]( asset_options& new_options )
{ new_options.flags &= ~disable_force_settle; } );
// Can't settle more BitUSD than you own
GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 999999, bitusd_id ) ), fc::exception );
// settle3 should be least collateralized order according to index
BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
BOOST_TEST_MESSAGE( "Verify partial settlement of call" );
// Partially settle a call
force_settlement_id_type settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
// Call does not take effect immediately
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
BOOST_CHECK_EQUAL( settle_id(db).balance.amount.value, 50);
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5780 );
BOOST_CHECK( settle_id(db).owner == nathan_id );
// Wait for settlement to take effect
generate_blocks(settle_id(db).settlement_date);
BOOST_CHECK(db.find(settle_id) == nullptr);
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 49 ); // 1% force_settlement_offset_percent (rounded unfavorably)
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 2950 );
BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5731 ); // 5731 == 5780-49
BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
BOOST_TEST_MESSAGE( "Verify pending settlement is cancelled when asset's force_settle is disabled" );
// Ensure pending settlement is cancelled when force settle is disabled
settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
BOOST_CHECK( !db.get_index_type<force_settlement_index>().indices().empty() );
update_asset_options( bitusd_id, [&]( asset_options& new_options )
{ new_options.flags |= disable_force_settle; } );
BOOST_CHECK( db.get_index_type<force_settlement_index>().indices().empty() );
update_asset_options( bitusd_id, [&]( asset_options& new_options )
{ new_options.flags &= ~disable_force_settle; } );
BOOST_TEST_MESSAGE( "Perform iterative settlement" );
settle_id = force_settle( nathan_id, asset( 12500, bitusd_id ) ).get< object_id_type >();
// c3 2950 : 5731 1.9427 fully settled
// c5 5000 : 9800 1.9600 fully settled
// c4 4000 : 7900 1.9750 fully settled
// c2 2000 : 3998 1.9990 550 settled
// c1 1000 : 2000 2.0000
generate_blocks( settle_id(db).settlement_date );
int64_t call1_payout = 0;
int64_t call2_payout = 550*99/100;
int64_t call3_payout = 49 + 2950*99/100;
int64_t call4_payout = 4000*99/100;
int64_t call5_payout = 5000*99/100;
BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2*1000 ); // full collat still tied up
BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-2*1999 ); // full collat still tied up
BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-call3_payout ); // initial balance minus transfer to Nathan (as BitUSD)
BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-call4_payout ); // initial balance minus transfer to Nathan (as BitUSD)
BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-call5_payout ); // initial balance minus transfer to Nathan (as BitUSD)
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id),
call1_payout + call2_payout + call3_payout + call4_payout + call5_payout );
BOOST_CHECK( db.find(call3_id) == nullptr );
BOOST_CHECK( db.find(call4_id) == nullptr );
BOOST_CHECK( db.find(call5_id) == nullptr );
BOOST_REQUIRE( db.find(call1_id) != nullptr );
BOOST_REQUIRE( db.find(call2_id) != nullptr );
BOOST_CHECK_EQUAL( call1_id(db).debt.value, 1000 );
BOOST_CHECK_EQUAL( call1_id(db).collateral.value, 2000 );
BOOST_CHECK_EQUAL( call2_id(db).debt.value, 2000-550 );
BOOST_CHECK_EQUAL( call2_id(db).collateral.value, 3998-call2_payout );
}
generate_block();
create_short(shorter1_id(db), asset(1000, bit_usd), asset(1000));
create_sell_order(nathan_id(db), asset(1000), asset(1000, bit_usd));
create_short(shorter2_id(db), asset(2000, bit_usd), asset(1999));
create_sell_order(nathan_id(db), asset(1999), asset(2000, bit_usd));
create_short(shorter3_id(db), asset(3000, bit_usd), asset(2990));
create_sell_order(nathan_id(db), asset(2990), asset(3000, bit_usd));
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), 6000);
transfer(nathan_id(db), account_id_type()(db), db.get_balance(nathan_id, asset_id_type()));
catch(fc::exception& e)
{
asset_update_bitasset_operation uop;
uop.issuer = bit_usd(db).issuer;
uop.asset_to_update = bit_usd;
uop.new_options = bit_usd(db).bitasset_data(db).options;
uop.new_options.force_settlement_delay_sec = 100;
uop.new_options.force_settlement_offset_percent = 100;
trx.operations.push_back(uop);
} {
asset_update_feed_producers_operation uop;
uop.asset_to_update = bit_usd;
uop.issuer = bit_usd(db).issuer;
uop.new_feed_producers = {nathan_id};
trx.operations.push_back(uop);
} {
asset_publish_feed_operation pop;
pop.asset_id = bit_usd;
pop.publisher = nathan_id;
price_feed feed;
feed.settlement_price = price(asset(1),asset(1, bit_usd));
feed.call_limit = price::min(0, bit_usd);
pop.feed = feed;
trx.operations.push_back(pop);
edump((e.to_detail_string()));
throw;
}
trx.sign(key_id_type(),private_key);
PUSH_TX( db, trx );
trx.clear();
asset_settle_operation sop;
sop.account = nathan_id;
sop.amount = asset(50, bit_usd);
trx.operations = {sop};
//Force settlement is disabled; check that it fails
GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception);
{
//Enable force settlement
asset_update_operation op;
op.issuer = bit_usd(db).issuer;
op.asset_to_update = bit_usd;
op.new_options = bit_usd(db).options;
op.new_options.flags &= ~disable_force_settle;
trx.operations = {op};
trx.sign(key_id_type(), private_key);
PUSH_TX( db, trx );
trx.operations = {sop};
}
REQUIRE_THROW_WITH_VALUE(sop, amount, asset(999999, bit_usd));
trx.operations.back() = sop;
trx.sign(key_id_type(),private_key);
//Partially settle a call
force_settlement_id_type settle_id = PUSH_TX( db, trx ).operation_results.front().get<object_id_type>();
trx.clear();
call_order_id_type call_id = db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id;
BOOST_CHECK_EQUAL(settle_id(db).balance.amount.value, 50);
BOOST_CHECK_EQUAL(call_id(db).debt.value, 3000);
BOOST_CHECK(settle_id(db).owner == nathan_id);
generate_blocks(settle_id(db).settlement_date);
BOOST_CHECK(db.find(settle_id) == nullptr);
BOOST_CHECK_EQUAL(get_balance(nathan_id, asset_id_type()), 49);
BOOST_CHECK_EQUAL(call_id(db).debt.value, 2950);
{
//Disable force settlement
asset_update_operation op;
op.issuer = bit_usd(db).issuer;
op.asset_to_update = bit_usd;
op.new_options = bit_usd(db).options;
op.new_options.flags |= disable_force_settle;
trx.operations.push_back(op);
trx.set_reference_block(db.head_block_id()); trx.set_expiration( db.head_block_time() + fc::seconds( 3 * db.get_global_properties().parameters.block_interval ) );
trx.sign(key_id_type(), private_key);
PUSH_TX( db, trx );
//Check that force settlements were all canceled
BOOST_CHECK(db.get_index_type<force_settlement_index>().indices().empty());
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), bit_usd(db).dynamic_data(db).current_supply.value);
}
} FC_LOG_AND_RETHROW()
*/
}
BOOST_AUTO_TEST_CASE( assert_op_test )