From ae3e01d4173d6bcdd150912eb52a2320ebbc4f7a Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 10 Aug 2019 16:19:41 -0400 Subject: [PATCH 1/3] Add APIs to query for general asset info - Add a `symbol` field in asset_bitasset_data_object - Add indices related to asset symbol - Add `get_assets_general_info` API - Add `list_assets_general_info` API --- libraries/app/api_objects.cpp | 17 ++ libraries/app/database_api.cpp | 150 ++++++++++++++++++ libraries/app/database_api_impl.hxx | 6 + .../app/include/graphene/app/api_objects.hpp | 30 ++++ .../app/include/graphene/app/database_api.hpp | 23 ++- libraries/chain/asset_evaluator.cpp | 1 + libraries/chain/asset_object.cpp | 1 + libraries/chain/db_init.cpp | 4 +- .../include/graphene/chain/asset_object.hpp | 40 +++-- .../chain/include/graphene/chain/config.hpp | 2 +- 10 files changed, 261 insertions(+), 13 deletions(-) diff --git a/libraries/app/api_objects.cpp b/libraries/app/api_objects.cpp index e002f061ae..625432a024 100644 --- a/libraries/app/api_objects.cpp +++ b/libraries/app/api_objects.cpp @@ -88,4 +88,21 @@ market_ticker::market_ticker(const fc::time_point_sec& now, quote_volume = "0"; } +general_asset_info::general_asset_info( const asset_object& a, const asset_bitasset_data_object* b ) +: id(a.id), symbol(a.symbol), precision(a.precision), issuer(a.issuer) +{ + if( id == asset_id_type() ) + type = CORE; + else if( !b ) + type = UIA; + else + { + if( b->is_prediction_market ) + type = PM; + else + type = MPA; + backing_asset_id = b->options.short_backing_asset; + } +} + } } // graphene::app diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d19a8daae2..66dd6d502b 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -863,6 +863,30 @@ vector> database_api_impl::get_assets( return result; } +vector> database_api::get_assets_general_info( + const vector& asset_symbols_or_ids ) const +{ + return my->get_assets_general_info( asset_symbols_or_ids ); +} + +vector> database_api_impl::get_assets_general_info( + const vector& asset_symbols_or_ids ) const +{ + vector> result; result.reserve(asset_symbols_or_ids.size()); + std::transform(asset_symbols_or_ids.begin(), asset_symbols_or_ids.end(), std::back_inserter(result), + [this](std::string id_or_name) -> optional { + + const asset_object* asset_obj = get_asset_from_string( id_or_name, false ); + if( asset_obj == nullptr ) + return {}; + const asset_bitasset_data_object* bitasset = nullptr; + if( asset_obj->is_market_issued() ) + bitasset = &asset_obj->bitasset_data(_db); + return general_asset_info( *asset_obj, bitasset ); + }); + return result; +} + vector database_api::list_assets(const string& lower_bound_symbol, uint32_t limit)const { return my->list_assets( lower_bound_symbol, limit ); @@ -888,6 +912,132 @@ vector database_api_impl::list_assets(const string& lower return result; } +vector database_api::list_assets_general_info( + optional lower_bound_symbol, + optional limit, + optional type )const +{ + return my->list_assets_general_info( lower_bound_symbol, limit, type ); +} + +vector database_api_impl::list_assets_general_info( + optional lower_bound_symbol, + optional olimit, + optional type )const +{ + uint32_t limit = olimit.valid() ? *olimit : 100; + uint64_t api_limit_get_assets = _app_options->api_limit_get_assets; + FC_ASSERT( limit <= api_limit_get_assets ); + + vector result; + if( limit == 0 ) + return result; + + result.reserve(limit); + + if( !type.valid() || *type == general_asset_info::ALL ) + { + const auto& assets_by_symbol = _db.get_index_type().indices().get(); + auto itr = lower_bound_symbol.valid() ? assets_by_symbol.lower_bound(*lower_bound_symbol) + : assets_by_symbol.begin(); + for( ; limit > 0 && itr != assets_by_symbol.end(); ++itr, --limit ) + { + const asset_object& asset_obj = *itr; + const asset_bitasset_data_object* bitasset = nullptr; + if( asset_obj.is_market_issued() ) + bitasset = &asset_obj.bitasset_data(_db); + result.emplace_back( asset_obj, bitasset ); + } + return result; + } + + const asset_object& core_asset = _db.get_core_asset(); + if( *type == general_asset_info::CORE ) + { + if( !lower_bound_symbol.valid() || *lower_bound_symbol <= core_asset.symbol ) + result.emplace_back( core_asset ); + return result; + } + + switch( *type ) + { + case general_asset_info::UIA : + case general_asset_info::CORE_OR_UIA : + case general_asset_info::MPA_OR_PM : + { + const auto& assets_by_type_symbol = _db.get_index_type().indices().get(); + auto itr = assets_by_type_symbol.begin(); + auto itr_end = assets_by_type_symbol.end(); + + if( *type == general_asset_info::MPA_OR_PM ) + { + if( lower_bound_symbol.valid() ) + itr = assets_by_type_symbol.lower_bound( boost::make_tuple( true, *lower_bound_symbol ) ); + else + itr = assets_by_type_symbol.lower_bound( true ); + } + else + { + itr_end = assets_by_type_symbol.lower_bound( true ); + if( lower_bound_symbol.valid() ) + itr = assets_by_type_symbol.lower_bound( boost::make_tuple( false, *lower_bound_symbol ) ); + // else itr = assets_by_type_symbol.begin() + } + + bool include_core = ( *type == general_asset_info::CORE_OR_UIA ); + bool mpa_or_pm = ( *type == general_asset_info::MPA_OR_PM ); + + for( ; limit > 0 && itr != itr_end; ++itr ) + { + const asset_object& asset_obj = *itr; + if( !include_core && (&asset_obj) == (&core_asset) ) + continue; + const asset_bitasset_data_object* bitasset = nullptr; + if( mpa_or_pm ) + bitasset = &asset_obj.bitasset_data(_db); + result.emplace_back( asset_obj, bitasset ); + --limit; + } + break; + } + case general_asset_info::MPA : + case general_asset_info::PM : + { + const auto& bitassets_by_type_symbol = _db.get_index_type().indices() + .get(); + auto itr = bitassets_by_type_symbol.begin(); + auto itr_end = bitassets_by_type_symbol.end(); + + if( *type == general_asset_info::PM ) + { + if( lower_bound_symbol.valid() ) + itr = bitassets_by_type_symbol.lower_bound( boost::make_tuple( true, *lower_bound_symbol ) ); + else + itr = bitassets_by_type_symbol.lower_bound( true ); + } + else + { + itr_end = bitassets_by_type_symbol.lower_bound( true ); + if( lower_bound_symbol.valid() ) + itr = bitassets_by_type_symbol.lower_bound( boost::make_tuple( false, *lower_bound_symbol ) ); + // else itr = bitassets_by_type_symbol.begin() + } + + for( ; limit > 0 && itr != itr_end; ++itr, --limit ) + { + const asset_bitasset_data_object& bitasset = *itr; + const asset_object& asset_obj = bitasset.asset_id(_db); + result.emplace_back( asset_obj, &bitasset ); + } + break; + } + default: // nothing here + break; + } + + return result; +} + uint64_t database_api::get_asset_count()const { return my->get_asset_count(); diff --git a/libraries/app/database_api_impl.hxx b/libraries/app/database_api_impl.hxx index e2e7c376a4..9c65a5c696 100644 --- a/libraries/app/database_api_impl.hxx +++ b/libraries/app/database_api_impl.hxx @@ -93,7 +93,13 @@ class database_api_impl : public std::enable_shared_from_this asset_id_type get_asset_id_from_string(const std::string& symbol_or_id)const; vector> get_assets( const vector& asset_symbols_or_ids, optional subscribe )const; + vector> get_assets_general_info( + const vector& asset_symbols_or_ids ) const; vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; + vector list_assets_general_info( + optional lower_bound_symbol, + optional limit, + optional type )const; vector> lookup_asset_symbols(const vector& symbols_or_ids)const; vector get_assets_by_issuer(const std::string& issuer_name_or_id, asset_id_type start, uint32_t limit)const; diff --git a/libraries/app/include/graphene/app/api_objects.hpp b/libraries/app/include/graphene/app/api_objects.hpp index af7a96e1ab..2f5866b112 100644 --- a/libraries/app/include/graphene/app/api_objects.hpp +++ b/libraries/app/include/graphene/app/api_objects.hpp @@ -146,6 +146,32 @@ namespace graphene { namespace app { optional total_backing_collateral; }; + /// General information of an asset + struct general_asset_info + { + /// General asset types + enum asset_type + { + CORE, ///< Core asset + UIA, ///< User-issued asset + MPA, ///< Market-pegged asset + PM, ///< Predition market + CORE_OR_UIA, ///< CORE or UIA, to be used as query parameter + MPA_OR_PM, ///< MPA or PM, to be used as query parameter + ALL ///< ALL, to be used as query parameter + }; + + explicit general_asset_info( const asset_object& a, + const asset_bitasset_data_object* b = nullptr ); + + asset_id_type id; ///< ID of this asset, i.e. "1.3.1" + string symbol; ///< Ticker symbol for this asset, i.e. "USD" + uint8_t precision = 0; ///< Maximum number of digits after the decimal point + account_id_type issuer; ///< ID of the account which created this asset + asset_type type; ///< Type of the asset + optional backing_asset_id; ///< ID of backing asset if this asset is a MPA or PM + }; + } } FC_REFLECT( graphene::app::more_data, @@ -184,3 +210,7 @@ FC_REFLECT( graphene::app::market_trade, (sequence)(date)(price)(amount)(value)( FC_REFLECT_DERIVED( graphene::app::extended_asset_object, (graphene::chain::asset_object), (total_in_collateral)(total_backing_collateral) ); + +FC_REFLECT( graphene::app::general_asset_info, (id)(symbol)(precision)(issuer)(type)(backing_asset_id) ) + +FC_REFLECT_ENUM( graphene::app::general_asset_info::asset_type, (CORE)(UIA)(MPA)(PM)(CORE_OR_UIA)(MPA_OR_PM)(ALL) ) diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 1960e64824..6814aa1141 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -386,13 +386,32 @@ class database_api optional subscribe = optional() )const; /** - * @brief Get assets alphabetically by symbol name + * @brief Get general info of a list of assets by symbol names or IDs + * @param asset_symbols_or_ids symbol names or IDs of the assets to retrieve + * @return General info of the assets corresponding to the provided symbol names or IDs + */ + vector> get_assets_general_info( + const vector& asset_symbols_or_ids ) const; + + /** + * @brief Get assets alphabetically ordered by symbol name * @param lower_bound_symbol Lower bound of symbol names to retrieve - * @param limit Maximum number of assets to fetch (must not exceed 101) + * @param limit Maximum number of assets to fetch * @return The assets found */ vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; + /** + * @brief Get general info of assets alphabetically ordered by symbol name + * @param lower_bound_symbol Lower bound of symbol names to retrieve, optional, empty string if omitted + * @param limit Maximum number of assets to fetch, optional, @a 100 if omitted + * @param type type of assets to fetch, optional, @a ALL if omitted + * @return General info of the assets found + */ + vector list_assets_general_info( optional lower_bound_symbol = {}, + optional limit = {}, + optional type = {} )const; + /** * @brief Get a list of assets by symbol names or IDs * @param symbols_or_ids symbol names or IDs of the assets to retrieve diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index e970790c7d..4ba970a7e9 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -152,6 +152,7 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; a.asset_id = next_asset_id; + a.symbol = op.symbol; }).id; const asset_object& new_asset = diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 50e874f858..6198b493e7 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -182,6 +182,7 @@ FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::asset_dynamic_data_object, (gra FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::asset_bitasset_data_object, (graphene::db::object), (asset_id) + (symbol) (feeds) (current_feed) (current_feed_publication_time) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 124cede1eb..1fba8ddea3 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -531,10 +531,12 @@ void database::init_genesis(const genesis_state_type& genesis_state) ++collateral_holder_number; } - bitasset_data_id = create([&core_asset,new_asset_id](asset_bitasset_data_object& b) { + bitasset_data_id = create( + [&core_asset,new_asset_id,&asset](asset_bitasset_data_object& b) { b.options.short_backing_asset = core_asset.id; b.options.minimum_feeds = GRAPHENE_DEFAULT_MINIMUM_FEEDS; b.asset_id = new_asset_id; + b.symbol = asset.symbol; }).id; } diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 3541f87f5b..a46b6bd08b 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -181,6 +181,9 @@ namespace graphene { namespace chain { /// The asset this object belong to asset_id_type asset_id; + /// The symbol of this asset + string symbol; + /// The tunable options for BitAssets are stored in this field. bitasset_options options; @@ -271,6 +274,8 @@ namespace graphene { namespace chain { } }; + struct by_symbol; + struct by_type_symbol; struct by_short_backing_asset; struct by_feed_expiration; struct by_cer_update; @@ -279,38 +284,55 @@ namespace graphene { namespace chain { asset_bitasset_data_object, indexed_by< ordered_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + member< asset_bitasset_data_object, string, &asset_bitasset_data_object::symbol > + >, + ordered_unique< tag, + composite_key< asset_bitasset_data_object, + member< asset_bitasset_data_object, bool, &asset_bitasset_data_object::is_prediction_market >, + member< asset_bitasset_data_object, string, &asset_bitasset_data_object::symbol > + > + >, ordered_non_unique< tag, bitasset_short_backing_asset_extractor >, ordered_unique< tag, composite_key< asset_bitasset_data_object, - const_mem_fun< asset_bitasset_data_object, time_point_sec, &asset_bitasset_data_object::feed_expiration_time >, + const_mem_fun< asset_bitasset_data_object, + time_point_sec, + &asset_bitasset_data_object::feed_expiration_time >, member< asset_bitasset_data_object, asset_id_type, &asset_bitasset_data_object::asset_id > > >, ordered_non_unique< tag, - const_mem_fun< asset_bitasset_data_object, bool, &asset_bitasset_data_object::need_to_update_cer > + const_mem_fun< asset_bitasset_data_object, bool, &asset_bitasset_data_object::need_to_update_cer > > > > asset_bitasset_data_object_multi_index_type; - typedef generic_index asset_bitasset_data_index; + typedef generic_index asset_bitasset_data_index; - struct by_symbol; struct by_type; struct by_issuer; typedef multi_index_container< asset_object, indexed_by< ordered_unique< tag, member< object, object_id_type, &object::id > >, - ordered_unique< tag, member >, + ordered_unique< tag, member >, ordered_unique< tag, composite_key< asset_object, - const_mem_fun, - member< object, object_id_type, &object::id > + const_mem_fun< asset_object, bool, &asset_object::is_market_issued >, + member< object, object_id_type, &object::id > + > + >, + ordered_unique< tag, + composite_key< asset_object, + const_mem_fun< asset_object, bool, &asset_object::is_market_issued >, + member< asset_object, string, &asset_object::symbol > > >, ordered_unique< tag, composite_key< asset_object, - member< asset_object, account_id_type, &asset_object::issuer >, - member< object, object_id_type, &object::id > + member< asset_object, account_id_type, &asset_object::issuer >, + member< object, object_id_type, &object::id > > > > diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 46a8feb54e..39d60dc7ab 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -30,7 +30,7 @@ #define GRAPHENE_MAX_NESTED_OBJECTS (200) -#define GRAPHENE_CURRENT_DB_VERSION "20190503" +#define GRAPHENE_CURRENT_DB_VERSION "20190810" #define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4 #define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3 From 39a1f515a8efebbef234969b1a017be73ab1c77b Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 10 Aug 2019 17:21:30 -0400 Subject: [PATCH 2/3] Reflect new APIs --- libraries/app/include/graphene/app/database_api.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 6814aa1141..cdb0de42b7 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -962,7 +962,9 @@ FC_API(graphene::app::database_api, // Assets (get_assets) + (get_assets_general_info) (list_assets) + (list_assets_general_info) (lookup_asset_symbols) (get_asset_count) (get_assets_by_issuer) From 64eae6bc0e1fd79774cbced9f7b9056a98bac620 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 10 Aug 2019 17:26:29 -0400 Subject: [PATCH 3/3] Add default constructor for general_asset_info --- libraries/app/include/graphene/app/api_objects.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/app/include/graphene/app/api_objects.hpp b/libraries/app/include/graphene/app/api_objects.hpp index 2f5866b112..3add85840d 100644 --- a/libraries/app/include/graphene/app/api_objects.hpp +++ b/libraries/app/include/graphene/app/api_objects.hpp @@ -161,6 +161,7 @@ namespace graphene { namespace app { ALL ///< ALL, to be used as query parameter }; + general_asset_info() {} explicit general_asset_info( const asset_object& a, const asset_bitasset_data_object* b = nullptr );