Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add database API to query for liquidity pools by any one asset in the pool #2365

Merged
merged 2 commits into from
Mar 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ database_api_impl::database_api_impl( graphene::chain::database& db, const appli
{
amount_in_collateral_index = nullptr;
}

try
{
asset_in_liquidity_pools_index = &_db.get_index_type< primary_index< liquidity_pool_index > >()
.get_secondary_index<graphene::api_helper_indexes::asset_in_liquidity_pools_index>();
}
catch( fc::assert_exception& e )
{
asset_in_liquidity_pools_index = nullptr;
}
}

database_api_impl::~database_api_impl()
Expand Down Expand Up @@ -1816,6 +1826,57 @@ vector<extended_liquidity_pool_object> database_api_impl::get_liquidity_pools_by
with_statistics );
}

vector<extended_liquidity_pool_object> database_api::get_liquidity_pools_by_one_asset(
std::string asset_symbol_or_id,
optional<uint32_t> limit,
optional<liquidity_pool_id_type> start_id,
optional<bool> with_statistics )const
{
return my->get_liquidity_pools_by_one_asset(
asset_symbol_or_id,
limit,
start_id,
with_statistics );
}

vector<extended_liquidity_pool_object> database_api_impl::get_liquidity_pools_by_one_asset(
std::string asset_symbol_or_id,
optional<uint32_t> olimit,
optional<liquidity_pool_id_type> ostart_id,
optional<bool> with_statistics )const
{
// api_helper_indexes plugin is required for accessing the secondary index
FC_ASSERT( _app_options && _app_options->has_api_helper_indexes_plugin,
"api_helper_indexes plugin is not enabled on this server." );

uint32_t limit = olimit.valid() ? *olimit : 101;
const auto configured_limit = _app_options->api_limit_get_liquidity_pools;
FC_ASSERT( limit <= configured_limit,
"limit can not be greater than ${configured_limit}",
("configured_limit", configured_limit) );

asset_id_type aid = get_asset_from_string(asset_symbol_or_id)->id;

FC_ASSERT( asset_in_liquidity_pools_index, "Internal error" );
const auto& pools = asset_in_liquidity_pools_index->get_liquidity_pools_by_asset( aid );

liquidity_pool_id_type start_id = ostart_id.valid() ? *ostart_id : liquidity_pool_id_type();

auto itr = pools.lower_bound( start_id );

bool with_stats = ( with_statistics.valid() && *with_statistics );

vector<extended_liquidity_pool_object> results;

results.reserve( limit );
for ( ; itr != pools.end() && results.size() < limit; ++itr )
{
results.emplace_back( extend_liquidity_pool( (*itr)(_db), with_stats ) );
}

return results;
}

vector<extended_liquidity_pool_object> database_api::get_liquidity_pools_by_both_assets(
std::string asset_symbol_or_id_a,
std::string asset_symbol_or_id_b,
Expand Down
6 changes: 6 additions & 0 deletions libraries/app/database_api_impl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
optional<uint32_t> limit = 101,
optional<liquidity_pool_id_type> start_id = optional<liquidity_pool_id_type>(),
optional<bool> with_statistics = false )const;
vector<extended_liquidity_pool_object> get_liquidity_pools_by_one_asset(
std::string asset_symbol_or_id,
optional<uint32_t> limit = 101,
optional<liquidity_pool_id_type> start_id = optional<liquidity_pool_id_type>(),
optional<bool> with_statistics = false )const;
vector<extended_liquidity_pool_object> get_liquidity_pools_by_both_assets(
std::string asset_symbol_or_id_a,
std::string asset_symbol_or_id_b,
Expand Down Expand Up @@ -465,6 +470,7 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
const application_options* _app_options = nullptr;

const graphene::api_helper_indexes::amount_in_collateral_index* amount_in_collateral_index;
const graphene::api_helper_indexes::asset_in_liquidity_pools_index* asset_in_liquidity_pools_index;
};

} } // graphene::app
21 changes: 21 additions & 0 deletions libraries/app/include/graphene/app/database_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,26 @@ class database_api
optional<liquidity_pool_id_type> start_id = optional<liquidity_pool_id_type>(),
optional<bool> with_statistics = false )const;

/**
* @brief Get a list of liquidity pools by the symbol or ID of one asset in the pool
* @param asset_symbol_or_id symbol name or ID of the asset
* @param limit The limitation of items each query can fetch, not greater than a configured value
* @param start_id Start liquidity pool id, fetch pools whose IDs are greater than or equal to this ID
* @param with_statistics Whether to return statistics
* @return The liquidity pools
*
* @note
* 1. if @p asset_symbol_or_id cannot be tied to an asset, an error will be returned
* 2. @p limit can be omitted or be null, if so the default value 101 will be used
* 3. @p start_id can be omitted or be null, if so the api will return the "first page" of pools
* 4. can only omit one or more arguments in the end of the list, but not one or more in the middle
*/
vector<extended_liquidity_pool_object> get_liquidity_pools_by_one_asset(
std::string asset_symbol_or_id,
optional<uint32_t> limit = 101,
optional<liquidity_pool_id_type> start_id = optional<liquidity_pool_id_type>(),
optional<bool> with_statistics = false )const;

/**
* @brief Get a list of liquidity pools by the symbols or IDs of the two assets in the pool
* @param asset_symbol_or_id_a symbol name or ID of one asset
Expand Down Expand Up @@ -1179,6 +1199,7 @@ FC_API(graphene::app::database_api,
(list_liquidity_pools)
(get_liquidity_pools_by_asset_a)
(get_liquidity_pools_by_asset_b)
(get_liquidity_pools_by_one_asset)
(get_liquidity_pools_by_both_assets)
(get_liquidity_pools)
(get_liquidity_pools_by_share_asset)
Expand Down
56 changes: 48 additions & 8 deletions libraries/plugins/api_helper_indexes/api_helper_indexes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

#include <graphene/api_helper_indexes/api_helper_indexes.hpp>
#include <graphene/chain/liquidity_pool_object.hpp>
#include <graphene/chain/market_object.hpp>
#include <graphene/chain/proposal_object.hpp>

Expand Down Expand Up @@ -78,19 +79,51 @@ void amount_in_collateral_index::object_modified( const object& objct )
object_inserted( objct );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

share_type amount_in_collateral_index::get_amount_in_collateral( const asset_id_type& asset )const
share_type amount_in_collateral_index::get_amount_in_collateral( const asset_id_type& asst )const
{ try {
auto itr = in_collateral.find( asset );
auto itr = in_collateral.find( asst );
if( itr == in_collateral.end() ) return 0;
return itr->second;
} FC_CAPTURE_AND_RETHROW( (asset) ); }
} FC_CAPTURE_AND_RETHROW( (asst) ); }

share_type amount_in_collateral_index::get_backing_collateral( const asset_id_type& asset )const
share_type amount_in_collateral_index::get_backing_collateral( const asset_id_type& asst )const
{ try {
auto itr = backing_collateral.find( asset );
auto itr = backing_collateral.find( asst );
if( itr == backing_collateral.end() ) return 0;
return itr->second;
} FC_CAPTURE_AND_RETHROW( (asset) ); }
} FC_CAPTURE_AND_RETHROW( (asst) ); }

void asset_in_liquidity_pools_index::object_inserted( const object& objct )
{ try {
const liquidity_pool_object& o = static_cast<const liquidity_pool_object&>( objct );
asset_in_pools_map[ o.asset_a ].insert( o.id ); // Note: [] operator will create an entry if not found
asset_in_pools_map[ o.asset_b ].insert( o.id );
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void asset_in_liquidity_pools_index::object_removed( const object& objct )
{ try {
const liquidity_pool_object& o = static_cast<const liquidity_pool_object&>( objct );
asset_in_pools_map[ o.asset_a ].erase( o.id );
asset_in_pools_map[ o.asset_b ].erase( o.id );
// Note: do not erase entries with an empty set from the map in order to avoid read/write race conditions
} FC_CAPTURE_AND_RETHROW( (objct) ); }

void asset_in_liquidity_pools_index::about_to_modify( const object& objct )
{
}

void asset_in_liquidity_pools_index::object_modified( const object& objct )
{
}

const flat_set<liquidity_pool_id_type>& asset_in_liquidity_pools_index::get_liquidity_pools_by_asset(
const asset_id_type& a )const
{
auto itr = asset_in_pools_map.find( a );
if( itr != asset_in_pools_map.end() )
return itr->second;
return empty_set;
}

namespace detail
{
Expand Down Expand Up @@ -147,9 +180,10 @@ void api_helper_indexes::plugin_initialize(const boost::program_options::variabl
void api_helper_indexes::plugin_startup()
{
ilog("api_helper_indexes: plugin_startup() begin");
amount_in_collateral = database().add_secondary_index< primary_index<call_order_index>, amount_in_collateral_index >();
amount_in_collateral_idx = database().add_secondary_index< primary_index<call_order_index>,
amount_in_collateral_index >();
for( const auto& call : database().get_index_type<call_order_index>().indices() )
amount_in_collateral->object_inserted( call );
amount_in_collateral_idx->object_inserted( call );

auto& account_members = *database().add_secondary_index< primary_index<account_index>, account_member_index >();
for( const auto& account : database().get_index_type< account_index >().indices() )
Expand All @@ -158,6 +192,12 @@ void api_helper_indexes::plugin_startup()
auto& approvals = *database().add_secondary_index< primary_index<proposal_index>, required_approval_index >();
for( const auto& proposal : database().get_index_type< proposal_index >().indices() )
approvals.object_inserted( proposal );

asset_in_liquidity_pools_idx = database().add_secondary_index< primary_index<liquidity_pool_index>,
asset_in_liquidity_pools_index >();
for( const auto& pool : database().get_index_type<liquidity_pool_index>().indices() )
asset_in_liquidity_pools_idx->object_inserted( pool );

}

} }
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ using namespace chain;
/**
* @brief This secondary index tracks how much of each asset is locked up as collateral for MPAs, and how much
* collateral is backing an MPA in total.
* @note This is implemented with \c flat_map considering there aren't too many MPAs and PMs in the system thus
* the performance would be acceptable.
*/
class amount_in_collateral_index : public secondary_index
{
Expand All @@ -49,6 +51,26 @@ class amount_in_collateral_index : public secondary_index
flat_map<asset_id_type, share_type> backing_collateral;
};

/**
* @brief This secondary index maintains a map to make it easier to find liquidity pools by any asset in the pool.
* @note This is implemented with \c flat_map and \c flat_set considering there aren't too many liquidity pools
* in the system thus the performance would be acceptable.
*/
class asset_in_liquidity_pools_index: public secondary_index
{
public:
virtual void object_inserted( const object& obj ) override;
virtual void object_removed( const object& obj ) override;
virtual void about_to_modify( const object& before ) override;
virtual void object_modified( const object& after ) override;

const flat_set<liquidity_pool_id_type>& get_liquidity_pools_by_asset( const asset_id_type& a )const;

private:
flat_set<liquidity_pool_id_type> empty_set;
flat_map<asset_id_type, flat_set<liquidity_pool_id_type>> asset_in_pools_map;
};

namespace detail
{
class api_helper_indexes_impl;
Expand All @@ -72,7 +94,8 @@ class api_helper_indexes : public graphene::app::plugin
std::unique_ptr<detail::api_helper_indexes_impl> my;

private:
amount_in_collateral_index* amount_in_collateral = nullptr;
amount_in_collateral_index* amount_in_collateral_idx = nullptr;
asset_in_liquidity_pools_index* asset_in_liquidity_pools_idx = nullptr;
};

} } //graphene::template