diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index edcfc2c3..2c8251ca 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -132,6 +132,27 @@ void database::cancel_order( const limit_order_object& order, bool create_virtua remove(order); } +bool maybe_cull_small_order( database& db, const limit_order_object& order ) +{ + /** + * There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we + * have hit the limit where the seller is asking for nothing in return. When this + * happens we must refund any balance back to the seller, it is too small to be + * sold at the sale price. + * + * If the order is a taker order (as opposed to a maker order), so the price is + * set by the counterparty, this check is deferred until the order becomes unmatched + * (see #555) -- however, detecting this condition is the responsibility of the caller. + */ + if( order.amount_to_receive().amount == 0 ) + { + ilog( "applied epsilon logic" ); + db.cancel_order(order); + return true; + } + return false; +} + bool database::apply_order(const limit_order_object& new_order_object, bool allow_black_swan) { auto order_id = new_order_object.id; @@ -171,7 +192,15 @@ bool database::apply_order(const limit_order_object& new_order_object, bool allo check_call_orders(sell_asset, allow_black_swan); check_call_orders(receive_asset, allow_black_swan); - return find_object(order_id) == nullptr; + const limit_order_object* updated_order_object = find< limit_order_object >( order_id ); + if( updated_order_object == nullptr ) + return true; + if( head_block_time() <= HARDFORK_555_TIME ) + return false; + // before #555 we would have done maybe_cull_small_order() logic as a result of fill_order() being called by match() above + // however after #555 we need to get rid of small orders -- #555 hardfork defers logic that was done too eagerly before, and + // this is the point it's deferred to. + return maybe_cull_small_order( *this, *updated_order_object ); } /** @@ -218,8 +247,8 @@ int database::match( const limit_order_object& usd, const OrderType& core, const core_pays == core.amount_for_sale() ); int result = 0; - result |= fill_order( usd, usd_pays, usd_receives ); - result |= fill_order( core, core_pays, core_receives ) << 1; + result |= fill_order( usd, usd_pays, usd_receives, false ); + result |= fill_order( core, core_pays, core_receives, true ) << 1; assert( result != 0 ); return result; } @@ -263,8 +292,10 @@ asset database::match( const call_order_object& call, return call_receives; } FC_CAPTURE_AND_RETHROW( (call)(settle)(match_price)(max_settlement) ) } -bool database::fill_order( const limit_order_object& order, const asset& pays, const asset& receives ) +bool database::fill_order( const limit_order_object& order, const asset& pays, const asset& receives, bool cull_if_small ) { try { + cull_if_small |= (head_block_time() < HARDFORK_555_TIME); + FC_ASSERT( order.amount_for_sale().asset_id == pays.asset_id ); FC_ASSERT( pays.asset_id != receives.asset_id ); @@ -297,17 +328,8 @@ bool database::fill_order( const limit_order_object& order, const asset& pays, c b.for_sale -= pays.amount; b.deferred_fee = 0; }); - /** - * There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we - * have hit the limit where the seller is asking for nothing in return. When this - * happens we must refund any balance back to the seller, it is too small to be - * sold at the sale price. - */ - if( order.amount_to_receive().amount == 0 ) - { - cancel_order(order); - return true; - } + if( cull_if_small ) + return maybe_cull_small_order( *this, order ); return false; } } FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) } @@ -517,7 +539,7 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan fill_order(*old_call_itr, call_pays, call_receives); auto old_limit_itr = filled_limit ? limit_itr++ : limit_itr; - fill_order(*old_limit_itr, order_pays, order_receives); + fill_order(*old_limit_itr, order_pays, order_receives, true); } // whlie call_itr != call_end diff --git a/libraries/chain/hardfork.d/555.hf b/libraries/chain/hardfork.d/555.hf new file mode 100644 index 00000000..28959f11 --- /dev/null +++ b/libraries/chain/hardfork.d/555.hf @@ -0,0 +1,4 @@ +// #555 Buyback accounts +#ifndef HARDFORK_555_TIME +#define HARDFORK_555_TIME (fc::time_point_sec( 1455127200 )) +#endif diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index e5956fec..a4dfdfc6 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -370,7 +370,7 @@ namespace graphene { namespace chain { /** * @return true if the order was completely filled and thus freed. */ - bool fill_order( const limit_order_object& order, const asset& pays, const asset& receives ); + bool fill_order( const limit_order_object& order, const asset& pays, const asset& receives, bool cull_if_small ); bool fill_order( const call_order_object& order, const asset& pays, const asset& receives ); bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives );