Compare commits
2 commits
master
...
GRPH-60-Pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31d8e68d89 | ||
|
|
dea5a973ba |
10 changed files with 340 additions and 2 deletions
|
|
@ -113,8 +113,15 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
|
||||||
vector<bet_object> get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const;
|
vector<bet_object> get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const;
|
||||||
vector<bet_object> get_all_unmatched_bets_for_bettor(account_id_type) const;
|
vector<bet_object> get_all_unmatched_bets_for_bettor(account_id_type) const;
|
||||||
|
|
||||||
|
const account_object* get_account_from_string( const std::string& name_or_id, bool throw_if_not_found = true ) const;
|
||||||
|
|
||||||
// Markets / feeds
|
// Markets / feeds
|
||||||
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
||||||
|
vector<limit_order_object> get_account_limit_orders( const string& account_name_or_id,
|
||||||
|
const string &base,
|
||||||
|
const string "e, uint32_t limit,
|
||||||
|
optional<limit_order_id_type> ostart_id,
|
||||||
|
optional<price> ostart_price );
|
||||||
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
|
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
|
||||||
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
|
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
|
||||||
vector<call_order_object> get_margin_positions( const account_id_type& id )const;
|
vector<call_order_object> get_margin_positions( const account_id_type& id )const;
|
||||||
|
|
@ -623,6 +630,92 @@ vector<optional<account_object>> database_api_impl::get_accounts(const vector<ac
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<limit_order_object> database_api::get_account_limit_orders( const string& account_name_or_id, const string &base,
|
||||||
|
const string "e, uint32_t limit, optional<limit_order_id_type> ostart_id, optional<price> ostart_price)
|
||||||
|
{
|
||||||
|
return my->get_account_limit_orders( account_name_or_id, base, quote, limit, ostart_id, ostart_price );
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<limit_order_object> database_api_impl::get_account_limit_orders( const string& account_name_or_id, const string &base,
|
||||||
|
const string "e, uint32_t limit, optional<limit_order_id_type> ostart_id, optional<price> ostart_price)
|
||||||
|
{
|
||||||
|
FC_ASSERT( limit <= 101 );
|
||||||
|
|
||||||
|
vector<limit_order_object> results;
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
const account_object* account = get_account_from_string(account_name_or_id);
|
||||||
|
if (account == nullptr)
|
||||||
|
return results;
|
||||||
|
|
||||||
|
auto assets = lookup_asset_symbols( {base, quote} );
|
||||||
|
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
|
||||||
|
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
|
||||||
|
|
||||||
|
auto base_id = assets[0]->id;
|
||||||
|
auto quote_id = assets[1]->id;
|
||||||
|
|
||||||
|
if (ostart_price.valid()) {
|
||||||
|
FC_ASSERT(ostart_price->base.asset_id == base_id, "Base asset inconsistent with start price");
|
||||||
|
FC_ASSERT(ostart_price->quote.asset_id == quote_id, "Quote asset inconsistent with start price");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& index_by_account = _db.get_index_type<limit_order_index>().indices().get<by_account>();
|
||||||
|
limit_order_multi_index_type::index<by_account>::type::const_iterator lower_itr;
|
||||||
|
limit_order_multi_index_type::index<by_account>::type::const_iterator upper_itr;
|
||||||
|
|
||||||
|
// if both order_id and price are invalid, query the first page
|
||||||
|
if ( !ostart_id.valid() && !ostart_price.valid() )
|
||||||
|
{
|
||||||
|
lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, price::max(base_id, quote_id)));
|
||||||
|
}
|
||||||
|
else if ( ostart_id.valid() )
|
||||||
|
{
|
||||||
|
// in case of the order been deleted during page querying
|
||||||
|
const limit_order_object *p_loo = _db.find(*ostart_id);
|
||||||
|
|
||||||
|
if ( !p_loo )
|
||||||
|
{
|
||||||
|
if ( ostart_price.valid() )
|
||||||
|
{
|
||||||
|
lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, *ostart_price, *ostart_id));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// start order id been deleted, yet not provided price either
|
||||||
|
FC_THROW("Order id invalid (maybe just been canceled?), and start price not provided");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const limit_order_object &loo = *p_loo;
|
||||||
|
|
||||||
|
// in case of the order not belongs to specified account or market
|
||||||
|
FC_ASSERT(loo.sell_price.base.asset_id == base_id, "Order base asset inconsistent");
|
||||||
|
FC_ASSERT(loo.sell_price.quote.asset_id == quote_id, "Order quote asset inconsistent with order");
|
||||||
|
FC_ASSERT(loo.seller == account->get_id(), "Order not owned by specified account");
|
||||||
|
|
||||||
|
lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, loo.sell_price, *ostart_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if reach here start_price must be valid
|
||||||
|
lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, *ostart_price));
|
||||||
|
}
|
||||||
|
|
||||||
|
upper_itr = index_by_account.upper_bound(std::make_tuple(account->id, price::min(base_id, quote_id)));
|
||||||
|
|
||||||
|
// Add the account's orders
|
||||||
|
for ( ; lower_itr != upper_itr && count < limit; ++lower_itr, ++count)
|
||||||
|
{
|
||||||
|
const limit_order_object &order = *lower_itr;
|
||||||
|
results.emplace_back(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<string,full_account> database_api::get_full_accounts( const vector<string>& names_or_ids, bool subscribe )
|
std::map<string,full_account> database_api::get_full_accounts( const vector<string>& names_or_ids, bool subscribe )
|
||||||
{
|
{
|
||||||
return my->get_full_accounts( names_or_ids, subscribe );
|
return my->get_full_accounts( names_or_ids, subscribe );
|
||||||
|
|
@ -1094,6 +1187,25 @@ vector<bet_object> database_api_impl::get_all_unmatched_bets_for_bettor(account_
|
||||||
return boost::copy_range<vector<bet_object> >(bet_idx.equal_range(std::make_tuple(bettor_id)));
|
return boost::copy_range<vector<bet_object> >(bet_idx.equal_range(std::make_tuple(bettor_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const account_object* database_api_impl::get_account_from_string( const std::string& name_or_id, bool throw_if_not_found) const
|
||||||
|
{
|
||||||
|
// TODO cache the result to avoid repeatly fetching from db
|
||||||
|
FC_ASSERT( name_or_id.size() > 0);
|
||||||
|
const account_object* account = nullptr;
|
||||||
|
if (std::isdigit(name_or_id[0]))
|
||||||
|
account = _db.find(fc::variant(name_or_id).as<account_id_type>());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||||
|
auto itr = idx.find(name_or_id);
|
||||||
|
if (itr != idx.end())
|
||||||
|
account = &*itr;
|
||||||
|
}
|
||||||
|
if(throw_if_not_found)
|
||||||
|
FC_ASSERT( account, "no such account" );
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// Markets / feeds //
|
// Markets / feeds //
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,36 @@ class database_api
|
||||||
*/
|
*/
|
||||||
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
|
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetch all orders relevant to the specified account and specified market, result orders
|
||||||
|
* are sorted descendingly by price
|
||||||
|
*
|
||||||
|
* @param account_name_or_id The name or ID of an account to retrieve
|
||||||
|
* @param base Base asset
|
||||||
|
* @param quote Quote asset
|
||||||
|
* @param limit The limitation of items each query can fetch, not greater than 101
|
||||||
|
* @param start_id Start order id, fetch orders which price lower than this order, or price equal to this order
|
||||||
|
* but order ID greater than this order
|
||||||
|
* @param start_price Fetch orders with price lower than or equal to this price
|
||||||
|
*
|
||||||
|
* @return List of orders from @ref account_name_or_id to the corresponding account
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* 1. if @ref account_name_or_id cannot be tied to an account, empty result will be returned
|
||||||
|
* 2. @ref start_id and @ref start_price can be empty, if so the api will return the "first page" of orders;
|
||||||
|
* if start_id is specified, its price will be used to do page query preferentially, otherwise the start_price
|
||||||
|
* will be used; start_id and start_price may be used cooperatively in case of the order specified by start_id
|
||||||
|
* was just canceled accidentally, in such case, the result orders' price may lower or equal to start_price,
|
||||||
|
* but orders' id greater than start_id
|
||||||
|
*/
|
||||||
|
|
||||||
|
vector<limit_order_object> get_account_limit_orders( const string& account_name_or_id,
|
||||||
|
const string &base,
|
||||||
|
const string "e,
|
||||||
|
uint32_t limit = 101,
|
||||||
|
optional<limit_order_id_type> ostart_id = optional<limit_order_id_type>(),
|
||||||
|
optional<price> ostart_price = optional<price>());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fetch all objects relevant to the specified accounts and subscribe to updates
|
* @brief Fetch all objects relevant to the specified accounts and subscribe to updates
|
||||||
* @param callback Function to call with updates
|
* @param callback Function to call with updates
|
||||||
|
|
@ -737,6 +767,7 @@ FC_API(graphene::app::database_api,
|
||||||
// Markets / feeds
|
// Markets / feeds
|
||||||
(get_order_book)
|
(get_order_book)
|
||||||
(get_limit_orders)
|
(get_limit_orders)
|
||||||
|
(get_account_limit_orders)
|
||||||
(get_call_orders)
|
(get_call_orders)
|
||||||
(get_settle_orders)
|
(get_settle_orders)
|
||||||
(get_margin_positions)
|
(get_margin_positions)
|
||||||
|
|
|
||||||
|
|
@ -325,6 +325,24 @@ processed_transaction database::validate_transaction( const signed_transaction&
|
||||||
return _apply_transaction( trx );
|
return _apply_transaction( trx );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class push_proposal_nesting_guard {
|
||||||
|
public:
|
||||||
|
push_proposal_nesting_guard( uint32_t& nesting_counter, const database& db )
|
||||||
|
: orig_value(nesting_counter), counter(nesting_counter)
|
||||||
|
{
|
||||||
|
FC_ASSERT( counter < db.get_global_properties().active_witnesses.size() * 2, "Max proposal nesting depth exceeded!" );
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
~push_proposal_nesting_guard()
|
||||||
|
{
|
||||||
|
if( --counter != orig_value )
|
||||||
|
elog( "Unexpected proposal nesting count value: ${n} != ${o}", ("n",counter)("o",orig_value) );
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const uint32_t orig_value;
|
||||||
|
uint32_t& counter;
|
||||||
|
};
|
||||||
|
|
||||||
processed_transaction database::push_proposal(const proposal_object& proposal)
|
processed_transaction database::push_proposal(const proposal_object& proposal)
|
||||||
{ try {
|
{ try {
|
||||||
transaction_evaluation_state eval_state(this);
|
transaction_evaluation_state eval_state(this);
|
||||||
|
|
@ -336,6 +354,9 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
|
||||||
size_t old_applied_ops_size = _applied_ops.size();
|
size_t old_applied_ops_size = _applied_ops.size();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
push_proposal_nesting_guard guard( _push_proposal_nesting_depth, *this );
|
||||||
|
if( _undo_db.size() >= _undo_db.max_size() )
|
||||||
|
_undo_db.set_max_size( _undo_db.size() + 1 );
|
||||||
auto session = _undo_db.start_undo_session(true);
|
auto session = _undo_db.start_undo_session(true);
|
||||||
for( auto& op : proposal.proposed_transaction.operations )
|
for( auto& op : proposal.proposed_transaction.operations )
|
||||||
eval_state.operation_results.emplace_back(apply_operation(eval_state, op));
|
eval_state.operation_results.emplace_back(apply_operation(eval_state, op));
|
||||||
|
|
|
||||||
|
|
@ -544,6 +544,8 @@ namespace graphene { namespace chain {
|
||||||
node_property_object _node_property_object;
|
node_property_object _node_property_object;
|
||||||
fc::hash_ctr_rng<secret_hash_type, 20> _random_number_generator;
|
fc::hash_ctr_rng<secret_hash_type, 20> _random_number_generator;
|
||||||
bool _slow_replays = false;
|
bool _slow_replays = false;
|
||||||
|
// Counts nested proposal updates
|
||||||
|
uint32_t _push_proposal_nesting_depth = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ typedef multi_index_container<
|
||||||
ordered_unique< tag<by_account>,
|
ordered_unique< tag<by_account>,
|
||||||
composite_key< limit_order_object,
|
composite_key< limit_order_object,
|
||||||
member<limit_order_object, account_id_type, &limit_order_object::seller>,
|
member<limit_order_object, account_id_type, &limit_order_object::seller>,
|
||||||
|
member<limit_order_object, price, &limit_order_object::sell_price>,
|
||||||
member<object, object_id_type, &object::id>
|
member<object, object_id_type, &object::id>
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ void proposal_update_operation::get_required_authorities( vector<authority>& o )
|
||||||
auth.key_auths[k] = 1;
|
auth.key_auths[k] = 1;
|
||||||
auth.weight_threshold = auth.key_auths.size();
|
auth.weight_threshold = auth.key_auths.size();
|
||||||
|
|
||||||
|
if( auth.weight_threshold > 0 )
|
||||||
o.emplace_back( std::move(auth) );
|
o.emplace_back( std::move(auth) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -372,6 +372,30 @@ class wallet_api
|
||||||
vector<account_balance_object> list_core_accounts()const;
|
vector<account_balance_object> list_core_accounts()const;
|
||||||
|
|
||||||
vector<bucket_object> get_market_history(string symbol, string symbol2, uint32_t bucket, fc::time_point_sec start, fc::time_point_sec end)const;
|
vector<bucket_object> get_market_history(string symbol, string symbol2, uint32_t bucket, fc::time_point_sec start, fc::time_point_sec end)const;
|
||||||
|
/**
|
||||||
|
* @brief Fetch all orders relevant to the specified account sorted descendingly by price
|
||||||
|
*
|
||||||
|
* @param name_or_id The name or ID of an account to retrieve
|
||||||
|
* @param base Base asset
|
||||||
|
* @param quote Quote asset
|
||||||
|
* @param limit The limitation of items each query can fetch (max: 101)
|
||||||
|
* @param ostart_id Start order id, fetch orders which price are lower than or equal to this order
|
||||||
|
* @param ostart_price Fetch orders with price lower than or equal to this price
|
||||||
|
*
|
||||||
|
* @return List of orders from \c name_or_id to the corresponding account
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* 1. if \c name_or_id cannot be tied to an account, empty result will be returned
|
||||||
|
* 2. \c ostart_id and \c ostart_price can be \c null, if so the api will return the "first page" of orders;
|
||||||
|
* if \c ostart_id is specified and valid, its price will be used to do page query preferentially,
|
||||||
|
* otherwise the \c ostart_price will be used
|
||||||
|
*/
|
||||||
|
vector<limit_order_object> get_account_limit_orders( const string& name_or_id,
|
||||||
|
const string &base,
|
||||||
|
const string "e,
|
||||||
|
uint32_t limit = 101,
|
||||||
|
optional<limit_order_id_type> ostart_id = optional<limit_order_id_type>(),
|
||||||
|
optional<price> ostart_price = optional<price>());
|
||||||
vector<limit_order_object> get_limit_orders(string a, string b, uint32_t limit)const;
|
vector<limit_order_object> get_limit_orders(string a, string b, uint32_t limit)const;
|
||||||
vector<call_order_object> get_call_orders(string a, uint32_t limit)const;
|
vector<call_order_object> get_call_orders(string a, uint32_t limit)const;
|
||||||
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
|
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
|
||||||
|
|
@ -1984,6 +2008,7 @@ FC_API( graphene::wallet::wallet_api,
|
||||||
(get_private_key)
|
(get_private_key)
|
||||||
(load_wallet_file)
|
(load_wallet_file)
|
||||||
(normalize_brain_key)
|
(normalize_brain_key)
|
||||||
|
(get_account_limit_orders)
|
||||||
(get_limit_orders)
|
(get_limit_orders)
|
||||||
(get_call_orders)
|
(get_call_orders)
|
||||||
(get_settle_orders)
|
(get_settle_orders)
|
||||||
|
|
|
||||||
|
|
@ -3522,6 +3522,17 @@ vector<bucket_object> wallet_api::get_market_history( string symbol1, string sym
|
||||||
return my->_remote_hist->get_market_history( get_asset_id(symbol1), get_asset_id(symbol2), bucket, start, end );
|
return my->_remote_hist->get_market_history( get_asset_id(symbol1), get_asset_id(symbol2), bucket, start, end );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<limit_order_object> wallet_api::get_account_limit_orders(
|
||||||
|
const string& name_or_id,
|
||||||
|
const string &base,
|
||||||
|
const string "e,
|
||||||
|
uint32_t limit,
|
||||||
|
optional<limit_order_id_type> ostart_id,
|
||||||
|
optional<price> ostart_price)
|
||||||
|
{
|
||||||
|
return my->_remote_db->get_account_limit_orders(name_or_id, base, quote, limit, ostart_id, ostart_price);
|
||||||
|
}
|
||||||
|
|
||||||
vector<limit_order_object> wallet_api::get_limit_orders(string a, string b, uint32_t limit)const
|
vector<limit_order_object> wallet_api::get_limit_orders(string a, string b, uint32_t limit)const
|
||||||
{
|
{
|
||||||
return my->_remote_db->get_limit_orders(get_asset(a).id, get_asset(b).id, limit);
|
return my->_remote_db->get_limit_orders(get_asset(a).id, get_asset(b).id, limit);
|
||||||
|
|
|
||||||
|
|
@ -894,7 +894,6 @@ BOOST_FIXTURE_TEST_CASE( max_authority_membership, database_fixture )
|
||||||
});
|
});
|
||||||
|
|
||||||
transaction tx;
|
transaction tx;
|
||||||
processed_transaction ptx;
|
|
||||||
|
|
||||||
private_key_type committee_key = init_account_priv_key;
|
private_key_type committee_key = init_account_priv_key;
|
||||||
// Sam is the creator of accounts
|
// Sam is the creator of accounts
|
||||||
|
|
@ -1313,4 +1312,58 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( nested_execution )
|
||||||
|
{ try {
|
||||||
|
ACTORS( (alice)(bob) );
|
||||||
|
fund( alice );
|
||||||
|
|
||||||
|
generate_blocks( fc::time_point::now() + fc::hours(1) );
|
||||||
|
set_expiration( db, trx );
|
||||||
|
|
||||||
|
const auto& gpo = db.get_global_properties();
|
||||||
|
|
||||||
|
proposal_create_operation pco;
|
||||||
|
pco.expiration_time = db.head_block_time() + fc::minutes(1);
|
||||||
|
pco.fee_paying_account = alice_id;
|
||||||
|
proposal_id_type inner;
|
||||||
|
{
|
||||||
|
transfer_operation top;
|
||||||
|
top.from = alice_id;
|
||||||
|
top.to = bob_id;
|
||||||
|
top.amount = asset( 10 );
|
||||||
|
pco.proposed_ops.emplace_back( top );
|
||||||
|
trx.operations.push_back( pco );
|
||||||
|
inner = PUSH_TX( db, trx, ~0 ).operation_results.front().get<object_id_type>();
|
||||||
|
trx.clear();
|
||||||
|
pco.proposed_ops.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<proposal_id_type> nested;
|
||||||
|
nested.push_back( inner );
|
||||||
|
for( size_t i = 0; i < gpo.active_witnesses.size() * 2; i++ )
|
||||||
|
{
|
||||||
|
proposal_update_operation pup;
|
||||||
|
pup.fee_paying_account = alice_id;
|
||||||
|
pup.proposal = nested.back();
|
||||||
|
pup.active_approvals_to_add.insert( alice_id );
|
||||||
|
pco.proposed_ops.emplace_back( pup );
|
||||||
|
trx.operations.push_back( pco );
|
||||||
|
nested.push_back( PUSH_TX( db, trx, ~0 ).operation_results.front().get<object_id_type>() );
|
||||||
|
trx.clear();
|
||||||
|
pco.proposed_ops.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
proposal_update_operation pup;
|
||||||
|
pup.fee_paying_account = alice_id;
|
||||||
|
pup.proposal = nested.back();
|
||||||
|
pup.active_approvals_to_add.insert( alice_id );
|
||||||
|
trx.operations.push_back( pup );
|
||||||
|
PUSH_TX( db, trx, ~0 );
|
||||||
|
|
||||||
|
for( size_t i = 1; i < nested.size(); i++ )
|
||||||
|
BOOST_CHECK_THROW( db.get<proposal_object>( nested[i] ), fc::assert_exception ); // executed successfully -> object removed
|
||||||
|
db.get<proposal_object>( inner ); // asn't executed -> object exists, doesn't throw
|
||||||
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
||||||
|
|
@ -68,4 +68,85 @@ BOOST_FIXTURE_TEST_SUITE(database_api_tests, database_fixture)
|
||||||
} FC_LOG_AND_RETHROW()
|
} FC_LOG_AND_RETHROW()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(get_account_limit_orders)
|
||||||
|
{ try {
|
||||||
|
|
||||||
|
ACTORS((seller));
|
||||||
|
|
||||||
|
const auto& bitcny = create_bitasset("CNY");
|
||||||
|
const auto& core = asset_id_type()(db);
|
||||||
|
|
||||||
|
int64_t init_balance(10000000);
|
||||||
|
transfer(committee_account, seller_id, asset(init_balance));
|
||||||
|
BOOST_CHECK_EQUAL( 10000000, get_balance(seller, core) );
|
||||||
|
|
||||||
|
/// Create 250 versatile orders
|
||||||
|
for (size_t i = 0 ; i < 50 ; ++i) {
|
||||||
|
BOOST_CHECK(create_sell_order(seller, core.amount(100), bitcny.amount(250)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 1 ; i < 101 ; ++i) {
|
||||||
|
BOOST_CHECK(create_sell_order(seller, core.amount(100), bitcny.amount(250 + i)));
|
||||||
|
BOOST_CHECK(create_sell_order(seller, core.amount(100), bitcny.amount(250 - i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
graphene::app::database_api db_api(db);
|
||||||
|
std::vector<limit_order_object> results;
|
||||||
|
limit_order_object o;
|
||||||
|
|
||||||
|
// query with no constraint, expected:
|
||||||
|
// 1. up to 101 orders returned
|
||||||
|
// 2. orders were sorted by price desendingly
|
||||||
|
results = db_api.get_account_limit_orders(seller.name, "BTS", "CNY");
|
||||||
|
BOOST_CHECK(results.size() == 101);
|
||||||
|
for (size_t i = 0 ; i < results.size() - 1 ; ++i) {
|
||||||
|
BOOST_CHECK(results[i].sell_price >= results[i+1].sell_price);
|
||||||
|
}
|
||||||
|
results.clear();
|
||||||
|
|
||||||
|
// query with specified limit, expected:
|
||||||
|
// 1. up to specified amount of orders returned
|
||||||
|
// 2. orders were sorted by price desendingly
|
||||||
|
results = db_api.get_account_limit_orders(seller.name, "BTS", "CNY", 50);
|
||||||
|
results = db_api.get_account_limit_orders(seller.name, "BTS", "CNY", 50);
|
||||||
|
BOOST_CHECK(results.size() == 50);
|
||||||
|
for (size_t i = 0 ; i < results.size() - 1 ; ++i) {
|
||||||
|
BOOST_CHECK(results[i].sell_price >= results[i+1].sell_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
o = results.back();
|
||||||
|
results.clear();
|
||||||
|
|
||||||
|
// query with specified order id and limit, expected:
|
||||||
|
// same as before, but also the first order's id equal to specified
|
||||||
|
results = db_api.get_account_limit_orders(seller.name, "BTS", "CNY", 100,
|
||||||
|
limit_order_id_type(o.id));
|
||||||
|
BOOST_CHECK(results.size() == 100);
|
||||||
|
BOOST_CHECK(results.front().id == o.id);
|
||||||
|
for (size_t i = 0 ; i < results.size() - 1 ; ++i) {
|
||||||
|
BOOST_CHECK(results[i].sell_price >= results[i+1].sell_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
o = results.back();
|
||||||
|
results.clear();
|
||||||
|
|
||||||
|
// query with specified price and an not exists order id, expected:
|
||||||
|
// 1. the canceled order should not exists in returned orders and first order's
|
||||||
|
// id should greater than specified
|
||||||
|
// 2. returned orders sorted by price desendingly
|
||||||
|
// 3. the first order's sell price equal to specified
|
||||||
|
cancel_limit_order(o); // NOTE 1: this canceled order was in scope of the
|
||||||
|
// first created 50 orders, so with price 2.5 BTS/CNY
|
||||||
|
results = db_api.get_account_limit_orders(seller.name, "BTS", "CNY", 101,
|
||||||
|
limit_order_id_type(o.id), o.sell_price);
|
||||||
|
BOOST_CHECK(results.size() <= 101);
|
||||||
|
BOOST_CHECK(results.front().id > o.id);
|
||||||
|
// NOTE 2: because of NOTE 1, here should be equal
|
||||||
|
BOOST_CHECK(results.front().sell_price == o.sell_price);
|
||||||
|
for (size_t i = 0 ; i < results.size() - 1 ; ++i) {
|
||||||
|
BOOST_CHECK(results[i].sell_price >= results[i+1].sell_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue