Skip to content

Commit

Permalink
Code refactory asset::multiply_and_round_up(price)
Browse files Browse the repository at this point in the history
  • Loading branch information
abitmore committed Apr 17, 2018
1 parent 2aedd11 commit c6b28b2
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 32 deletions.
2 changes: 1 addition & 1 deletion libraries/chain/asset_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ operation_result asset_settle_evaluator::do_apply(const asset_settle_evaluator::
&& settled_amount.amount != 0
&& d.get_dynamic_global_properties().next_maintenance_time > HARDFORK_CORE_342_TIME )
{
pays = settled_amount ^ bitasset.settlement_price;
pays = settled_amount.multiply_and_round_up( bitasset.settlement_price );
}

d.adjust_balance( op.account, -pays );
Expand Down
18 changes: 9 additions & 9 deletions libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett
wlog( "Something for nothing issue (#184, variant E) occurred at block #${block}", ("block",head_block_num()) );
}
else
pays = call_itr->get_debt() ^ settlement_price; // round up, in favor of global settlement fund
pays = call_itr->get_debt().multiply_and_round_up( settlement_price ); // round up, in favor of global settlement fund

if( pays > call_itr->get_collateral() )
pays = call_itr->get_collateral();
Expand Down Expand Up @@ -539,7 +539,7 @@ int database::match( const limit_order_object& usd, const limit_order_object& co
// so we should cull the order in fill_limit_order() below.
// The order would receive 0 even at `match_price`, so it would receive 0 at its own price,
// so calling maybe_cull_small() will always cull it.
core_receives = usd_receives ^ match_price;
core_receives = usd_receives.multiply_and_round_up( match_price );
cull_taker = true;
}
}
Expand All @@ -557,7 +557,7 @@ int database::match( const limit_order_object& usd, const limit_order_object& co
else
// The remaining amount in order `core` would be too small,
// so the order will be culled in fill_limit_order() below
usd_receives = core_receives ^ match_price;
usd_receives = core_receives.multiply_and_round_up( match_price );
}

core_pays = usd_receives;
Expand Down Expand Up @@ -608,7 +608,7 @@ int database::match( const limit_order_object& bid, const call_order_object& ask
// so we should cull the order in fill_limit_order() below.
// The order would receive 0 even at `match_price`, so it would receive 0 at its own price,
// so calling maybe_cull_small() will always cull it.
call_receives = order_receives ^ match_price;
call_receives = order_receives.multiply_and_round_up( match_price );
cull_taker = true;
}
}
Expand All @@ -623,7 +623,7 @@ int database::match( const limit_order_object& bid, const call_order_object& ask
return 1;
}
else // has hardfork core-342
order_receives = usd_to_buy ^ match_price; // round up here, in favor of limit order
order_receives = usd_to_buy.multiply_and_round_up( match_price ); // round up here, in favor of limit order
}

call_pays = order_receives;
Expand Down Expand Up @@ -688,7 +688,7 @@ asset database::match( const call_order_object& call,
{
if( call_receives == call_debt ) // the call order is smaller than or equal to the settle order
{
call_pays = call_receives ^ match_price; // round up here, in favor of settle order
call_pays = call_receives.multiply_and_round_up( match_price ); // round up here, in favor of settle order
// be here, we should have: call_pays <= call_collateral
}
else
Expand All @@ -701,7 +701,7 @@ asset database::match( const call_order_object& call,
cull_settle_order = true;
// else do nothing, since we can't cull the settle order

call_receives = call_pays ^ match_price; // round up here to mitigate rounding issue (core-342)
call_receives = call_pays.multiply_and_round_up( match_price ); // round up here to mitigate rounding issue (core-342)

if( call_receives == settle.balance ) // the settle order will be completely filled, no need to cull
cull_settle_order = false;
Expand Down Expand Up @@ -1007,7 +1007,7 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan
// so we should cull the order in fill_limit_order() below.
// The order would receive 0 even at `match_price`, so it would receive 0 at its own price,
// so calling maybe_cull_small() will always cull it.
call_receives = order_receives ^ match_price;
call_receives = order_receives.multiply_and_round_up( match_price );

filled_limit = true;

Expand All @@ -1023,7 +1023,7 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan
wlog( "Something for nothing issue (#184, variant D) occurred at block #${block}", ("block",head_block_num()) );
}
else
order_receives = usd_to_buy ^ match_price; // round up, in favor of limit order
order_receives = usd_to_buy.multiply_and_round_up( match_price ); // round up, in favor of limit order

filled_call = true;

Expand Down
5 changes: 4 additions & 1 deletion libraries/chain/include/graphene/chain/protocol/asset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ namespace graphene { namespace chain {

extern const int64_t scaled_precision_lut[];

struct price;

struct asset
{
asset( share_type a = 0, asset_id_type id = asset_id_type() )
Expand Down Expand Up @@ -94,6 +96,8 @@ namespace graphene { namespace chain {
FC_ASSERT( precision < 19 );
return scaled_precision_lut[ precision ];
}

asset multiply_and_round_up( const price& p )const; ///< Multiply and round up
};

/**
Expand Down Expand Up @@ -145,7 +149,6 @@ namespace graphene { namespace chain {
bool operator == ( const price& a, const price& b );
bool operator != ( const price& a, const price& b );
asset operator * ( const asset& a, const price& b ); ///< Multiply and round down
asset operator ^ ( const asset& a, const price& b ); ///< Multiply and round up

price operator * ( const price& p, const ratio_type& r );
price operator / ( const price& p, const ratio_type& r );
Expand Down
5 changes: 3 additions & 2 deletions libraries/chain/protocol/asset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ namespace graphene { namespace chain {
FC_THROW_EXCEPTION( fc::assert_exception, "invalid asset * price", ("asset",a)("price",b) );
}

asset operator ^ ( const asset& a, const price& b )
asset asset::multiply_and_round_up( const price& b )const
{
const asset& a = *this;
if( a.asset_id == b.base.asset_id )
{
FC_ASSERT( b.base.amount.value > 0 );
Expand All @@ -108,7 +109,7 @@ namespace graphene { namespace chain {
FC_ASSERT( result <= GRAPHENE_MAX_SHARE_SUPPLY );
return asset( result.convert_to<int64_t>(), b.base.asset_id );
}
FC_THROW_EXCEPTION( fc::assert_exception, "invalid asset * price", ("asset",a)("price",b) );
FC_THROW_EXCEPTION( fc::assert_exception, "invalid asset::multiply_and_round_up(price)", ("asset",a)("price",b) );
}

price operator / ( const asset& base, const asset& quote )
Expand Down
40 changes: 21 additions & 19 deletions tests/tests/basic_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,29 +261,31 @@ BOOST_AUTO_TEST_CASE( price_test )
BOOST_CHECK_THROW( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1) * price( asset(1), asset(2, asset_id_type(1)) ), fc::assert_exception );
BOOST_CHECK_THROW( asset(2) * price( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1, asset_id_type(1)), asset(1) ), fc::assert_exception );

// Note: `==` executes before `^`, so need `( a ^ b ) == c`
BOOST_CHECK( ( asset(1) ^ price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1, asset_id_type(1)) );
BOOST_CHECK( ( asset(1) ^ price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1, asset_id_type(1)) );
BOOST_CHECK( ( asset(1, asset_id_type(1)) ^ price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1) );
BOOST_CHECK( ( asset(1, asset_id_type(1)) ^ price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1) );

BOOST_CHECK( ( asset(3) ^ price( asset(3), asset(5, asset_id_type(1)) ) ) == asset(5, asset_id_type(1)) ); // round_up(3*5/3)
BOOST_CHECK( ( asset(5) ^ price( asset(2, asset_id_type(1)), asset(7) ) ) == asset(2, asset_id_type(1)) ); // round_up(5*2/7)
BOOST_CHECK( ( asset(7, asset_id_type(1)) ^ price( asset(2), asset(3, asset_id_type(1)) ) ) == asset(5) ); // round_up(7*2/3)
BOOST_CHECK( ( asset(9, asset_id_type(1)) ^ price( asset(8, asset_id_type(1)), asset(7) ) ) == asset(8) ); // round_up(9*7/8)
BOOST_CHECK( asset(1).multiply_and_round_up( price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1, asset_id_type(1)) );
BOOST_CHECK( asset(1).multiply_and_round_up( price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1, asset_id_type(1)) );
BOOST_CHECK( asset(1, asset_id_type(1)).multiply_and_round_up( price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1) );
BOOST_CHECK( asset(1, asset_id_type(1)).multiply_and_round_up( price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1) );

// round_up(3*5/3)
BOOST_CHECK( asset(3).multiply_and_round_up( price( asset(3), asset(5, asset_id_type(1)) ) ) == asset(5, asset_id_type(1)) );
// round_up(5*2/7)
BOOST_CHECK( asset(5).multiply_and_round_up( price( asset(2, asset_id_type(1)), asset(7) ) ) == asset(2, asset_id_type(1)) );
// round_up(7*2/3)
BOOST_CHECK( asset(7, asset_id_type(1)).multiply_and_round_up( price( asset(2), asset(3, asset_id_type(1)) ) ) == asset(5) );
// round_up(9*7/8)
BOOST_CHECK( asset(9, asset_id_type(1)).multiply_and_round_up( price( asset(8, asset_id_type(1)), asset(7) ) ) == asset(8) );

// asset and price doesn't match
BOOST_CHECK_THROW( asset(1, asset_id_type(3)) ^ price( asset(1, asset_id_type(2)), asset(1) ), fc::assert_exception );
BOOST_CHECK_THROW( asset(1, asset_id_type(3)).multiply_and_round_up( price( asset(1, asset_id_type(2)), asset(1) ) ),
fc::assert_exception );
// divide by zero
BOOST_CHECK_THROW( asset(1) ^ price( asset(0), asset(1, asset_id_type(1)) ), fc::assert_exception );
BOOST_CHECK_THROW( asset(1) ^ price( asset(1, asset_id_type(1)), asset(0) ), fc::assert_exception );
BOOST_CHECK_THROW( asset(1).multiply_and_round_up( price( asset(0), asset(1, asset_id_type(1)) ) ), fc::assert_exception );
BOOST_CHECK_THROW( asset(1).multiply_and_round_up( price( asset(1, asset_id_type(1)), asset(0) ) ), fc::assert_exception );
// overflow
BOOST_CHECK_THROW( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1) ^ price( asset(1), asset(2, asset_id_type(1)) ), fc::assert_exception );
BOOST_CHECK_THROW( asset(2) ^ price( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1, asset_id_type(1)), asset(1) ), fc::assert_exception );

// checks that operator^() executes before operator=()
auto x = asset(3) ^ price( asset(6), asset(10, asset_id_type(1)) );
BOOST_CHECK( x == asset(5, asset_id_type(1)) );
BOOST_CHECK_THROW( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1).multiply_and_round_up( price( asset(1), asset(2, asset_id_type(1)) ) ),
fc::assert_exception );
BOOST_CHECK_THROW( asset(2).multiply_and_round_up( price( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1, asset_id_type(1)), asset(1) ) ),
fc::assert_exception );

price_feed dummy;
dummy.maintenance_collateral_ratio = 1002;
Expand Down

0 comments on commit c6b28b2

Please sign in to comment.