diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 90576296c6..9b906c3f1a 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -546,6 +546,127 @@ namespace graphene { namespace app { return result; } FC_CAPTURE_AND_RETHROW( (asset_a)(asset_b)(bucket_seconds)(start)(end) ) } + vector history_api::get_liquidity_pool_history( + liquidity_pool_id_type pool_id, + optional start, + optional stop, + optional olimit, + optional operation_type )const + { try { + FC_ASSERT( _app.get_options().has_market_history_plugin, "Market history plugin is not enabled." ); + + uint32_t limit = olimit.valid() ? *olimit : 101; + + const auto configured_limit = _app.get_options().api_limit_get_account_history_by_operations; + FC_ASSERT( limit <= configured_limit, + "limit can not be greater than ${configured_limit}", + ("configured_limit", configured_limit) ); + + FC_ASSERT( _app.chain_database(), "Internal error: the chain database is not availalbe" ); + + const auto& db = *_app.chain_database(); + + vector result; + + if( limit == 0 || ( start.valid() && stop.valid() && *start <= *stop ) ) // empty result + return result; + + const auto& hist_idx = db.get_index_type(); + + if( operation_type.valid() ) // one operation type + { + const auto& idx = hist_idx.indices().get(); + auto itr = start.valid() ? idx.lower_bound( boost::make_tuple( pool_id, *operation_type, *start ) ) + : idx.lower_bound( boost::make_tuple( pool_id, *operation_type ) ); + auto itr_stop = stop.valid() ? idx.upper_bound( boost::make_tuple( pool_id, *operation_type, *stop ) ) + : idx.upper_bound( boost::make_tuple( pool_id, *operation_type ) ); + while( itr != itr_stop && result.size() < limit ) + { + result.push_back( *itr ); + ++itr; + } + } + else // all operation types + { + const auto& idx = hist_idx.indices().get(); + auto itr = start.valid() ? idx.lower_bound( boost::make_tuple( pool_id, *start ) ) + : idx.lower_bound( pool_id ); + auto itr_stop = stop.valid() ? idx.upper_bound( boost::make_tuple( pool_id, *stop ) ) + : idx.upper_bound( pool_id ); + while( itr != itr_stop && result.size() < limit ) + { + result.push_back( *itr ); + ++itr; + } + } + + return result; + + } FC_CAPTURE_AND_RETHROW( (pool_id)(start)(stop)(olimit)(operation_type) ) } + + vector history_api::get_liquidity_pool_history_by_sequence( + liquidity_pool_id_type pool_id, + optional start, + optional stop, + optional olimit, + optional operation_type )const + { try { + FC_ASSERT( _app.get_options().has_market_history_plugin, "Market history plugin is not enabled." ); + + uint32_t limit = olimit.valid() ? *olimit : 101; + + const auto configured_limit = _app.get_options().api_limit_get_account_history_by_operations; + FC_ASSERT( limit <= configured_limit, + "limit can not be greater than ${configured_limit}", + ("configured_limit", configured_limit) ); + + FC_ASSERT( _app.chain_database(), "Internal error: the chain database is not availalbe" ); + + const auto& db = *_app.chain_database(); + + vector result; + + if( limit == 0 ) // empty result + return result; + + const auto& hist_idx = db.get_index_type(); + + if( operation_type.valid() ) // one operation type + { + const auto& idx = hist_idx.indices().get(); + const auto& idx_t = hist_idx.indices().get(); + auto itr = start.valid() ? idx.lower_bound( boost::make_tuple( pool_id, *operation_type, *start ) ) + : idx.lower_bound( boost::make_tuple( pool_id, *operation_type ) ); + auto itr_temp = stop.valid() ? idx_t.upper_bound( boost::make_tuple( pool_id, *operation_type, *stop ) ) + : idx_t.upper_bound( boost::make_tuple( pool_id, *operation_type ) ); + auto itr_stop = ( itr_temp == idx_t.end() ? idx.end() : idx.iterator_to( *itr_temp ) ); + while( itr != itr_stop && result.size() < limit ) + { + result.push_back( *itr ); + ++itr; + } + } + else // all operation types + { + const auto& idx = hist_idx.indices().get(); + const auto& idx_t = hist_idx.indices().get(); + auto itr = start.valid() ? idx.lower_bound( boost::make_tuple( pool_id, *start ) ) + : idx.lower_bound( pool_id ); + auto itr_temp = stop.valid() ? idx_t.upper_bound( boost::make_tuple( pool_id, *stop ) ) + : idx_t.upper_bound( pool_id ); + auto itr_stop = ( itr_temp == idx_t.end() ? idx.end() : idx.iterator_to( *itr_temp ) ); + while( itr != itr_stop && result.size() < limit ) + { + result.push_back( *itr ); + ++itr; + } + } + + return result; + + } FC_CAPTURE_AND_RETHROW( (pool_id)(start)(stop)(olimit)(operation_type) ) } + + crypto_api::crypto_api(){}; commitment_type crypto_api::blind( const blind_factor_type& blind, uint64_t value ) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index cf0d81c807..6c09532b98 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -326,11 +326,15 @@ void application_impl::set_api_limit() { if(_options->count("api-limit-get-withdraw-permissions-by-recipient")) { _app_options.api_limit_get_withdraw_permissions_by_recipient = _options->at("api-limit-get-withdraw-permissions-by-recipient").as(); } - if(_options->count("api-limit-get-liquidity-pools")) { + if(_options->count("api-limit-get-tickets") > 0) { + _app_options.api_limit_get_tickets = _options->at("api-limit-get-tickets").as(); + } + if(_options->count("api-limit-get-liquidity-pools") > 0) { _app_options.api_limit_get_liquidity_pools = _options->at("api-limit-get-liquidity-pools").as(); } - if(_options->count("api-limit-get-tickets")) { - _app_options.api_limit_get_tickets = _options->at("api-limit-get-tickets").as(); + if(_options->count("api-limit-get-liquidity-pool-history") > 0) { + _app_options.api_limit_get_liquidity_pool_history = + _options->at("api-limit-get-liquidity-pool-history").as(); } } @@ -1060,10 +1064,12 @@ void application::set_program_options(boost::program_options::options_descriptio "For database_api_impl::get_withdraw_permissions_by_giver to set max limit value") ("api-limit-get-withdraw-permissions-by-recipient",boost::program_options::value()->default_value(101), "For database_api_impl::get_withdraw_permissions_by_recipient to set max limit value") - ("api-limit-get-liquidity-pools",boost::program_options::value()->default_value(101), - "For database_api_impl::get_liquidity_pools_* to set max limit value") - ("api-limit-get-tickets",boost::program_options::value()->default_value(101), - "For database_api_impl::get_tickets_* to set max limit value") + ("api-limit-get-tickets", boost::program_options::value()->default_value(101), + "Set maximum limit value for database APIs which query for tickets") + ("api-limit-get-liquidity-pools", boost::program_options::value()->default_value(101), + "Set maximum limit value for database APIs which query for liquidity pools") + ("api-limit-get-liquidity-pool-history", boost::program_options::value()->default_value(101), + "Set maximum limit value for APIs which query for history of liquidity pools") ; command_line_options.add(configuration_file_options); command_line_options.add_options() diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 92c08c266a..e680188219 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -220,6 +220,65 @@ namespace graphene { namespace app { * it means this API server supports OHLCV data aggregated in 5-minute buckets. */ flat_set get_market_history_buckets()const; + + /** + * @brief Get history of a liquidity pool + * @param pool_id ID of the liquidity pool to query + * @param start A UNIX timestamp. Optional. + * If specified, only the operations occurred not later than this time will be returned. + * @param stop A UNIX timestamp. Optional. + * If specified, only the operations occurred later than this time will be returned. + * @param limit Maximum quantity of operations in the history to retrieve. + * Optional. If not specified, at most 101 records will be returned. + * @param operation_type Optional. If specified, only the operations whose type is the specified type + * will be returned. Otherwise all operations will be returned. + * @return operation history of the liquidity pool, ordered by time, most recent first. + * + * @note + * 1. The time must be UTC. The range is (stop, start]. + * 2. In case when there are more than 100 operations occurred in the same second, this API only returns + * the most recent records, the rest records can be retrieved with the + * @ref get_liquidity_pool_history_by_sequence API. + * 3. List of operation type code: 59-creation, 60-deletion, 61-deposit, 62-withdrawal, 63-exchange. + * 4. Can only omit one or more arguments in the end of the list, but not one or more in the middle. + * If need to not specify an individual argument, can specify \c null in the place. + */ + vector get_liquidity_pool_history( + liquidity_pool_id_type pool_id, + optional start = optional(), + optional stop = optional(), + optional limit = 101, + optional operation_type = optional() )const; + + /** + * @brief Get history of a liquidity pool + * @param pool_id ID of the liquidity pool to query + * @param start An Integer. Optional. + * If specified, only the operations whose sequences are not greater than this will be returned. + * @param stop A UNIX timestamp. Optional. + * If specified, only operations occurred later than this time will be returned. + * @param limit Maximum quantity of operations in the history to retrieve. + * Optional. If not specified, at most 101 records will be returned. + * @param operation_type Optional. If specified, only the operations whose type is the specified type + * will be returned. Otherwise all operations will be returned. + * @return operation history of the liquidity pool, ordered by time, most recent first. + * + * @note + * 1. The time must be UTC. The range is (stop, start]. + * 2. In case when there are more than 100 operations occurred in the same second, this API only returns + * the most recent records, the rest records can be retrieved with the + * @ref get_liquidity_pool_history_by_sequence API. + * 3. List of operation type code: 59-creation, 60-deletion, 61-deposit, 62-withdrawal, 63-exchange. + * 4. Can only omit one or more arguments in the end of the list, but not one or more in the middle. + * If need to not specify an individual argument, can specify \c null in the place. + */ + vector get_liquidity_pool_history_by_sequence( + liquidity_pool_id_type pool_id, + optional start = optional(), + optional stop = optional(), + optional limit = 101, + optional operation_type = optional() )const; + private: application& _app; graphene::app::database_api database_api; @@ -645,6 +704,8 @@ FC_API(graphene::app::history_api, (get_fill_order_history) (get_market_history) (get_market_history_buckets) + (get_liquidity_pool_history) + (get_liquidity_pool_history_by_sequence) ) FC_API(graphene::app::block_api, (get_blocks) diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 7c331cb5b0..f3f54ae54e 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -72,8 +72,9 @@ namespace graphene { namespace app { uint64_t api_limit_get_trade_history_by_sequence = 100; uint64_t api_limit_get_withdraw_permissions_by_giver = 101; uint64_t api_limit_get_withdraw_permissions_by_recipient = 101; - uint64_t api_limit_get_liquidity_pools = 101; uint64_t api_limit_get_tickets = 101; + uint64_t api_limit_get_liquidity_pools = 101; + uint64_t api_limit_get_liquidity_pool_history = 101; }; class application diff --git a/libraries/plugins/market_history/include/graphene/market_history/market_history_plugin.hpp b/libraries/plugins/market_history/include/graphene/market_history/market_history_plugin.hpp index 09a71ce6ad..4007b11d15 100644 --- a/libraries/plugins/market_history/include/graphene/market_history/market_history_plugin.hpp +++ b/libraries/plugins/market_history/include/graphene/market_history/market_history_plugin.hpp @@ -236,6 +236,8 @@ struct liquidity_pool_history_object : public abstract_object, std::greater< uint64_t > > + >, + ordered_unique< tag, + composite_key< liquidity_pool_history_object, + member, + member, + member + >, + composite_key_compare< + std::less< liquidity_pool_id_type >, + std::less< int64_t >, + std::greater< uint64_t > + > + >, + ordered_unique< tag, + composite_key< liquidity_pool_history_object, + member, + member, + member, + member + >, + composite_key_compare< + std::less< liquidity_pool_id_type >, + std::less< int64_t >, + std::greater< time_point_sec >, + std::greater< uint64_t > + > > > > liquidity_pool_history_multi_index_type;