diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index fab06cda..57c6ada5 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -103,7 +103,7 @@ namespace graphene { namespace app { } else if( api_name == "asset_api" ) { - _asset_api = std::make_shared< asset_api >( std::ref( *_app.chain_database() ) ); + _asset_api = std::make_shared< asset_api >( _app ); } else if( api_name == "debug_api" ) { @@ -526,10 +526,12 @@ namespace graphene { namespace app { } // end get_relevant_accounts( obj ) #endif - vector history_api::get_fill_order_history( asset_id_type a, asset_id_type b, uint32_t limit )const + vector history_api::get_fill_order_history( std::string asset_a, std::string asset_b, uint32_t limit )const { FC_ASSERT(_app.chain_database()); const auto& db = *_app.chain_database(); + asset_id_type a = database_api.get_asset_id_from_string( asset_a ); + asset_id_type b = database_api.get_asset_id_from_string( asset_b ); if( a > b ) std::swap(a,b); const auto& history_idx = db.get_index_type().indices().get(); history_key hkey; @@ -679,11 +681,13 @@ namespace graphene { namespace app { return hist->tracked_buckets(); } - vector history_api::get_market_history( asset_id_type a, asset_id_type b, + vector history_api::get_market_history( std::string asset_a, std::string asset_b, uint32_t bucket_seconds, fc::time_point_sec start, fc::time_point_sec end )const { try { FC_ASSERT(_app.chain_database()); const auto& db = *_app.chain_database(); + asset_id_type a = database_api.get_asset_id_from_string( asset_a ); + asset_id_type b = database_api.get_asset_id_from_string( asset_b ); vector result; result.reserve(200); @@ -703,7 +707,7 @@ namespace graphene { namespace app { ++itr; } return result; - } FC_CAPTURE_AND_RETHROW( (a)(b)(bucket_seconds)(start)(end) ) } + } FC_CAPTURE_AND_RETHROW( (asset_a)(asset_b)(bucket_seconds)(start)(end) ) } crypto_api::crypto_api(){}; @@ -762,12 +766,16 @@ namespace graphene { namespace app { } // asset_api - asset_api::asset_api(graphene::chain::database& db) : _db(db) { } + asset_api::asset_api(graphene::app::application& app) : + _app(app), + _db( *app.chain_database()), + database_api( std::ref(*app.chain_database())) { } asset_api::~asset_api() { } - vector asset_api::get_asset_holders( asset_id_type asset_id, uint32_t start, uint32_t limit ) const { + vector asset_api::get_asset_holders( std::string asset, uint32_t start, uint32_t limit ) const { FC_ASSERT(limit <= 100); + asset_id_type asset_id = database_api.get_asset_id_from_string( asset ); const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >(); auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) ); @@ -798,11 +806,11 @@ namespace graphene { namespace app { return result; } // get number of asset holders. - int asset_api::get_asset_holders_count( asset_id_type asset_id ) const { + int asset_api::get_asset_holders_count( std::string asset ) const { const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >(); auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) ); - + asset_id_type asset_id = database_api.get_asset_id_from_string( asset ); int count = boost::distance(range) - 1; return count; diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 3ea62c6c..7d62d25f 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -97,7 +97,11 @@ class database_api_impl : public std::enable_shared_from_this vector get_vesting_balances( const std::string account_id_or_name )const; // Assets - vector> get_assets(const vector& asset_ids)const; + asset_id_type get_asset_id_from_string(const std::string& symbol_or_id)const; + vector> get_assets(const vector& asset_symbols_or_ids)const; + // helper function + vector> get_assets( const vector& asset_ids, + optional subscribe = optional() )const; vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; vector> lookup_asset_symbols(const vector& symbols_or_ids)const; uint64_t get_asset_count()const; @@ -124,12 +128,15 @@ class database_api_impl : public std::enable_shared_from_this asset get_sweeps_vesting_balance_available_for_claim( account_id_type account )const; // Markets / feeds - vector get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const; - vector get_call_orders(asset_id_type a, uint32_t limit)const; - vector get_settle_orders(asset_id_type a, uint32_t limit)const; + vector get_limit_orders( const asset_id_type a, const asset_id_type b, + const uint32_t limit )const; + vector get_limit_orders( const std::string& a, const std::string& b, + uint32_t limit)const; + vector get_call_orders(const std::string& a, uint32_t limit)const; + vector get_settle_orders(const std::string& a, uint32_t limit)const; vector get_margin_positions( const std::string account_id_or_name )const; - void subscribe_to_market(std::function callback, asset_id_type a, asset_id_type b); - void unsubscribe_from_market(asset_id_type a, asset_id_type b); + void subscribe_to_market(std::function callback, const std::string& a, const std::string& b); + void unsubscribe_from_market(const std::string& a, const std::string& b); market_ticker get_ticker( const string& base, const string& quote )const; market_volume get_24_volume( const string& base, const string& quote )const; order_book get_order_book( const string& base, const string& quote, unsigned limit = 50 )const; @@ -157,7 +164,7 @@ class database_api_impl : public std::enable_shared_from_this bool verify_authority( const signed_transaction& trx )const; bool verify_account_authority( const string& name_or_id, const flat_set& signers )const; processed_transaction validate_transaction( const signed_transaction& trx )const; - vector< fc::variant > get_required_fees( const vector& ops, asset_id_type id )const; + vector< fc::variant > get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const; // Proposed transactions vector get_proposed_transactions( const std::string account_id_or_name )const; @@ -177,6 +184,8 @@ class database_api_impl : public std::enable_shared_from_this //private: const account_object* get_account_from_string( const std::string& name_or_id, bool throw_if_not_found = true ) const; + const asset_object* get_asset_from_string( const std::string& symbol_or_id, + bool throw_if_not_found = true ) const; template void subscribe_to_item( const T& i )const { @@ -954,9 +963,48 @@ vector database_api_impl::get_vesting_balances( const st // // ////////////////////////////////////////////////////////////////////// -vector> database_api::get_assets(const vector& asset_ids)const +asset_id_type database_api::get_asset_id_from_string(const std::string& symbol_or_id)const { - return my->get_assets( asset_ids ); + return my->get_asset_from_string( symbol_or_id )->id; +} + +const asset_object* database_api_impl::get_asset_from_string( const std::string& symbol_or_id, + bool throw_if_not_found ) const +{ + // TODO cache the result to avoid repeatly fetching from db + FC_ASSERT( symbol_or_id.size() > 0); + const asset_object* asset = nullptr; + if (std::isdigit(symbol_or_id[0])) + asset = _db.find(fc::variant(symbol_or_id, 1).as(1)); + else + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(symbol_or_id); + if (itr != idx.end()) + asset = &*itr; + } + if(throw_if_not_found) + FC_ASSERT( asset, "no such asset" ); + return asset; +} + +vector> database_api::get_assets(const vector& asset_symbols_or_ids)const +{ + return my->get_assets( asset_symbols_or_ids ); +} + +vector> database_api_impl::get_assets(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 {}; + subscribe_to_item(asset_obj->id ); + return asset_object( *asset_obj ); + }); + return result; } vector> database_api_impl::get_assets(const vector& asset_ids)const @@ -1212,7 +1260,7 @@ vector database_api_impl::get_all_unmatched_bets_for_bettor(account_ // // ////////////////////////////////////////////////////////////////////// -vector database_api::get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const +vector database_api::get_limit_orders(const std::string& a, const std::string& b, uint32_t limit)const { return my->get_limit_orders( a, b, limit ); } @@ -1220,12 +1268,28 @@ vector database_api::get_limit_orders(asset_id_type a, asset /** * @return the limit orders for both sides of the book for the two assets specified up to limit number on each side. */ -vector database_api_impl::get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const +vector database_api_impl::get_limit_orders(const std::string& a, const std::string& b, uint32_t limit)const { + uint64_t api_limit_get_limit_orders=_app_options->api_limit_get_limit_orders; + FC_ASSERT( limit <= api_limit_get_limit_orders ); + + const asset_id_type asset_a_id = get_asset_from_string(a)->id; + const asset_id_type asset_b_id = get_asset_from_string(b)->id; + + return get_limit_orders(asset_a_id, asset_b_id, limit); +} + +vector database_api_impl::get_limit_orders( const asset_id_type a, const asset_id_type b, + const uint32_t limit )const +{ + uint64_t api_limit_get_limit_orders=_app_options->api_limit_get_limit_orders; + FC_ASSERT( limit <= api_limit_get_limit_orders ); + const auto& limit_order_idx = _db.get_index_type(); const auto& limit_price_idx = limit_order_idx.indices().get(); vector result; + result.reserve(limit*2); uint32_t count = 0; auto limit_itr = limit_price_idx.lower_bound(price::max(a,b)); @@ -1249,30 +1313,30 @@ vector database_api_impl::get_limit_orders(asset_id_type a, return result; } -vector database_api::get_call_orders(asset_id_type a, uint32_t limit)const +vector database_api::get_call_orders(const std::string& a, uint32_t limit)const { return my->get_call_orders( a, limit ); } -vector database_api_impl::get_call_orders(asset_id_type a, uint32_t limit)const +vector database_api_impl::get_call_orders(const std::string& a, uint32_t limit)const { const auto& call_index = _db.get_index_type().indices().get(); - const asset_object& mia = _db.get(a); + const asset_object* mia = get_asset_from_string(a); price index_price = price::min(mia.bitasset_data(_db).options.short_backing_asset, mia.get_id()); return vector(call_index.lower_bound(index_price.min()), call_index.lower_bound(index_price.max())); } -vector database_api::get_settle_orders(asset_id_type a, uint32_t limit)const +vector database_api::get_settle_orders(const std::string& a, uint32_t limit)const { return my->get_settle_orders( a, limit ); } -vector database_api_impl::get_settle_orders(asset_id_type a, uint32_t limit)const +vector database_api_impl::get_settle_orders(const std::string& a, uint32_t limit)const { const auto& settle_index = _db.get_index_type().indices().get(); - const asset_object& mia = _db.get(a); + const asset_object& mia = get_asset_from_string(a); return vector(settle_index.lower_bound(mia.get_id()), settle_index.upper_bound(mia.get_id())); } @@ -1301,28 +1365,34 @@ vector database_api_impl::get_margin_positions( const std::st } FC_CAPTURE_AND_RETHROW( (account_id_or_name) ) } -void database_api::subscribe_to_market(std::function callback, asset_id_type a, asset_id_type b) +void database_api::subscribe_to_market(std::function callback, const std::string& a, const std::string& b) { my->subscribe_to_market( callback, a, b ); } -void database_api_impl::subscribe_to_market(std::function callback, asset_id_type a, asset_id_type b) +void database_api_impl::subscribe_to_market(std::function callback, const std::string& a, const std::string& b) { - if(a > b) std::swap(a,b); - FC_ASSERT(a != b); - _market_subscriptions[ std::make_pair(a,b) ] = callback; + auto asset_a_id = get_asset_from_string(a)->id; + auto asset_b_id = get_asset_from_string(b)->id; + + if(asset_a_id > asset_b_id) std::swap(asset_a_id,asset_b_id); + FC_ASSERT(asset_a_id != asset_b_id); + _market_subscriptions[ std::make_pair(asset_a_id,asset_b_id) ] = callback; } -void database_api::unsubscribe_from_market(asset_id_type a, asset_id_type b) +void database_api::unsubscribe_from_market(const std::string& a, const std::string& b) { my->unsubscribe_from_market( a, b ); } -void database_api_impl::unsubscribe_from_market(asset_id_type a, asset_id_type b) +void database_api_impl::unsubscribe_from_market(const std::string& a, const std::string& b) { - if(a > b) std::swap(a,b); - FC_ASSERT(a != b); - _market_subscriptions.erase(std::make_pair(a,b)); + auto asset_a_id = get_asset_from_string(a)->id; + auto asset_b_id = get_asset_from_string(b)->id; + + if(asset_a_id > asset_b_id) std::swap(asset_a_id,asset_b_id); + FC_ASSERT(asset_a_id != asset_b_id); + _market_subscriptions.erase(std::make_pair(asset_a_id,asset_b_id)); } market_ticker database_api::get_ticker( const string& base, const string& quote )const @@ -1548,7 +1618,7 @@ vector> database_api::get_witnesses(const vector database_api::get_workers_by_account(const std::string account_id_or_name)const { const auto& idx = my->_db.get_index_type().indices().get(); - const account_id_type account = get_account_from_string(account_id_or_name)->id; + const account_id_type account = my->get_account_from_string(account_id_or_name)->id; auto itr = idx.find(account); vector result; @@ -1911,7 +1981,7 @@ processed_transaction database_api_impl::validate_transaction( const signed_tran return _db.validate_transaction(trx); } -vector< fc::variant > database_api::get_required_fees( const vector& ops, asset_id_type id )const +vector< fc::variant > database_api::get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const { return my->get_required_fees( ops, id ); } @@ -1972,7 +2042,7 @@ struct get_required_fees_helper uint32_t current_recursion = 0; }; -vector< fc::variant > database_api_impl::get_required_fees( const vector& ops, asset_id_type id )const +vector< fc::variant > database_api_impl::get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const { vector< operation > _ops = ops; // @@ -1982,7 +2052,7 @@ vector< fc::variant > database_api_impl::get_required_fees( const vector result; result.reserve(ops.size()); - const asset_object& a = id(_db); + const asset_object& a = *get_asset_from_string(asset_id_or_symbol); get_required_fees_helper helper( _db.current_fee_schedule(), a.options.core_exchange_rate, diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 126bc0b4..d40dde6e 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -96,7 +96,7 @@ namespace graphene { namespace app { { public: history_api(application& app) - :_app(app), database_api( std::ref(*app.chain_database()), &(app.get_options())) {} + :_app(app), database_api( std::ref(*app.chain_database())) {} /** * @brief Get operations relevant to the specificed account @@ -143,8 +143,8 @@ namespace graphene { namespace app { unsigned limit = 100, uint32_t start = 0) const; - vector get_fill_order_history( asset_id_type a, asset_id_type b, uint32_t limit )const; - vector get_market_history( asset_id_type a, asset_id_type b, uint32_t bucket_seconds, + vector get_fill_order_history( std::string asset_a, std::string asset_b, uint32_t limit )const; + vector get_market_history( std::string asset_a, std::string asset_b, uint32_t bucket_seconds, fc::time_point_sec start, fc::time_point_sec end )const; vector list_core_accounts()const; flat_set get_market_history_buckets()const; @@ -327,15 +327,35 @@ namespace graphene { namespace app { class asset_api { public: - asset_api(graphene::chain::database& db); + asset_api(graphene::app::application& app); ~asset_api(); - vector get_asset_holders( asset_id_type asset_id, uint32_t start, uint32_t limit )const; - int get_asset_holders_count( asset_id_type asset_id )const; + /** + * @brief Get asset holders for a specific asset + * @param asset The specific asset id or symbol + * @param start The start index + * @param limit Maximum limit must not exceed 100 + * @return A list of asset holders for the specified asset + */ + vector get_asset_holders( std::string asset, uint32_t start, uint32_t limit )const; + + /** + * @brief Get asset holders count for a specific asset + * @param asset The specific asset id or symbol + * @return Holders count for the specified asset + */ + int get_asset_holders_count( std::string asset )const; + + /** + * @brief Get all asset holders + * @return A list of all asset holders + */ vector get_all_asset_holders() const; private: + graphene::app::application& _app; graphene::chain::database& _db; + graphene::app::database_api database_api; }; /** diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index f5cf3ac7..00f51a44 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -334,14 +334,21 @@ class database_api // Assets // //////////// + /** + * @brief Get asset ID from an asset symbol or ID + * @param symbol_or_id symbol name or ID of the asset + * @return asset ID + */ + asset_id_type get_asset_id_from_string(const std::string& symbol_or_id) const; + /** * @brief Get a list of assets by ID - * @param asset_ids IDs of the assets to retrieve + * @param asset_symbols_or_ids IDs or names of the assets to retrieve * @return The assets corresponding to the provided IDs * * This function has semantics identical to @ref get_objects */ - vector> get_assets(const vector& asset_ids)const; + vector> get_assets(const vector& asset_symbols_or_ids)const; /** * @brief Get assets alphabetically by symbol name @@ -443,23 +450,23 @@ class database_api * @param limit Maximum number of orders to retrieve * @return The limit orders, ordered from least price to greatest */ - vector get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const; + vector get_limit_orders(const std::string& a, const std::string& b, uint32_t limit)const; /** * @brief Get call orders in a given asset - * @param a ID of asset being called + * @param a ID or name of asset being called * @param limit Maximum number of orders to retrieve * @return The call orders, ordered from earliest to be called to latest */ - vector get_call_orders(asset_id_type a, uint32_t limit)const; + vector get_call_orders(const std::string& a, uint32_t limit)const; /** * @brief Get forced settlement orders in a given asset - * @param a ID of asset being settled + * @param a ID or name of asset being settled * @param limit Maximum number of orders to retrieve * @return The settle orders, ordered from earliest settlement date to latest */ - vector get_settle_orders(asset_id_type a, uint32_t limit)const; + vector get_settle_orders(const std::string& a, uint32_t limit)const; /** * @return all open margin positions for a given account id. @@ -469,21 +476,21 @@ class database_api /** * @brief Request notification when the active orders in the market between two assets changes * @param callback Callback method which is called when the market changes - * @param a First asset ID - * @param b Second asset ID + * @param a First asset ID or name + * @param b Second asset ID or name * * Callback will be passed a variant containing a vector>. The vector will * contain, in order, the operations which changed the market, and their results. */ void subscribe_to_market(std::function callback, - asset_id_type a, asset_id_type b); + const std::string& a, const std::string& b); /** * @brief Unsubscribe from updates to a given market - * @param a First asset ID - * @param b Second asset ID + * @param a First asset ID or name + * @param b Second asset ID or name */ - void unsubscribe_from_market( asset_id_type a, asset_id_type b ); + void unsubscribe_from_market( const std::string& a, const std::string& b ); /** * @brief Returns the ticker for the market assetA:assetB @@ -650,7 +657,7 @@ class database_api * For each operation calculate the required fee in the specified asset type. If the asset type does * not have a valid core_exchange_rate */ - vector< fc::variant > get_required_fees( const vector& ops, asset_id_type id )const; + vector< fc::variant > get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const; /////////////////////////// // Proposed transactions // @@ -766,6 +773,7 @@ FC_API(graphene::app::database_api, (list_assets) (lookup_asset_symbols) (get_asset_count) + (get_asset_id_from_string) // Peerplays (list_sports) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 3d881300..8c99788c 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -762,9 +762,16 @@ public: { return get_account(account_name_or_id).get_id(); } + std::string asset_id_to_string(asset_id_type id) const + { + std::string asset_id = fc::to_string(id.space_id) + + "." + fc::to_string(id.type_id) + + "." + fc::to_string(id.instance.value); + return asset_id; + } optional find_asset(asset_id_type id)const { - auto rec = _remote_db->get_assets({id}).front(); + auto rec = _remote_db->get_assets({asset_id_to_string(id)}).front(); if( rec ) _asset_cache[id] = *rec; return rec; @@ -3738,8 +3745,7 @@ asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const vector wallet_api::get_account_history(string name, int limit) const { vector result; - auto account_id = get_account(name).get_id(); - + while (limit > 0) { bool skip_first_row = false; @@ -3759,7 +3765,7 @@ vector wallet_api::get_account_history(string name, int limit) int page_limit = skip_first_row ? std::min(100, limit + 1) : std::min(100, limit); - vector current = my->_remote_hist->get_account_history(account_id, operation_history_id_type(), + vector current = my->_remote_hist->get_account_history(name, operation_history_id_type(), page_limit, start); bool first_row = true; for (auto &o : current) @@ -3818,22 +3824,22 @@ vector wallet_api::list_core_accounts()const vector wallet_api::get_market_history( string symbol1, string symbol2, uint32_t bucket , fc::time_point_sec start, fc::time_point_sec end )const { - 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( symbol1, symbol2, bucket, start, end ); } vector 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(a, b, limit); } vector wallet_api::get_call_orders(string a, uint32_t limit)const { - return my->_remote_db->get_call_orders(get_asset(a).id, limit); + return my->_remote_db->get_call_orders(a, limit); } vector wallet_api::get_settle_orders(string a, uint32_t limit)const { - return my->_remote_db->get_settle_orders(get_asset(a).id, limit); + return my->_remote_db->get_settle_orders(a, limit); } brain_key_info wallet_api::suggest_brain_key()const