BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
database_api.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "database_api_impl.hxx"
26 
27 #include <graphene/app/util.hpp>
29 #include <graphene/chain/hardfork.hpp>
32 
33 #include <fc/crypto/hex.hpp>
35 
36 #include <boost/range/iterator_range.hpp>
37 
38 #include <cctype>
39 
41 
42 namespace graphene { namespace app {
43 
45 // //
46 // Constructors //
47 // //
49 
50 database_api::database_api( graphene::chain::database& db, const application_options* app_options )
51  : my( new database_api_impl( db, app_options ) ) {}
52 
54 
56 :_db(db), _app_options(app_options)
57 {
58  dlog("creating database api ${x}", ("x",int64_t(this)) );
59  _new_connection = _db.new_objects.connect([this](const vector<object_id_type>& ids,
60  const flat_set<account_id_type>& impacted_accounts) {
61  on_objects_new(ids, impacted_accounts);
62  });
63  _change_connection = _db.changed_objects.connect([this](const vector<object_id_type>& ids,
64  const flat_set<account_id_type>& impacted_accounts) {
65  on_objects_changed(ids, impacted_accounts);
66  });
67  _removed_connection = _db.removed_objects.connect([this](const vector<object_id_type>& ids,
68  const vector<const object*>& objs,
69  const flat_set<account_id_type>& impacted_accounts) {
70  on_objects_removed(ids, objs, impacted_accounts);
71  });
73 
74  _pending_trx_connection = _db.on_pending_transaction.connect([this](const signed_transaction& trx ){
77  });
78  try
79  {
81  .get_secondary_index<graphene::api_helper_indexes::amount_in_collateral_index>();
82  }
83  catch( fc::assert_exception& e )
84  {
86  }
87 }
88 
90 {
91  dlog("freeing database api ${x}", ("x",int64_t(this)) );
92 }
93 
95 // //
96 // Objects //
97 // //
99 
100 fc::variants database_api::get_objects( const vector<object_id_type>& ids, optional<bool> subscribe )const
101 {
102  return my->get_objects( ids, subscribe );
103 }
104 
105 fc::variants database_api_impl::get_objects( const vector<object_id_type>& ids, optional<bool> subscribe )const
106 {
107  bool to_subscribe = get_whether_to_subscribe( subscribe );
108 
109  fc::variants result;
110  result.reserve(ids.size());
111 
112  std::transform(ids.begin(), ids.end(), std::back_inserter(result),
113  [this,to_subscribe](object_id_type id) -> fc::variant {
114  if(auto obj = _db.find_object(id))
115  {
116  if( to_subscribe && !id.is<operation_history_id_type>() && !id.is<account_transaction_history_id_type>() )
117  this->subscribe_to_item( id );
118  return obj->to_variant();
119  }
120  return {};
121  });
122 
123  return result;
124 }
125 
127 // //
128 // Subscriptions //
129 // //
131 
132 void database_api::set_subscribe_callback( std::function<void(const variant&)> cb, bool notify_remove_create )
133 {
134  my->set_subscribe_callback( cb, notify_remove_create );
135 }
136 
137 void database_api_impl::set_subscribe_callback( std::function<void(const variant&)> cb, bool notify_remove_create )
138 {
139  if( notify_remove_create )
140  {
142  "Subscribing to universal object creation and removal is disallowed in this server." );
143  }
144 
145  cancel_all_subscriptions(false, false);
146 
147  _subscribe_callback = cb;
148  _notify_remove_create = notify_remove_create;
149 }
150 
152 {
153  my->set_auto_subscription( enable );
154 }
155 
157 {
159 }
160 
161 void database_api::set_pending_transaction_callback( std::function<void(const variant&)> cb )
162 {
163  my->set_pending_transaction_callback( cb );
164 }
165 
166 void database_api_impl::set_pending_transaction_callback( std::function<void(const variant&)> cb )
167 {
169 }
170 
171 void database_api::set_block_applied_callback( std::function<void(const variant& block_id)> cb )
172 {
173  my->set_block_applied_callback( cb );
174 }
175 
176 void database_api_impl::set_block_applied_callback( std::function<void(const variant& block_id)> cb )
177 {
179 }
180 
182 {
183  my->cancel_all_subscriptions(true, true);
184 }
185 
186 void database_api_impl::cancel_all_subscriptions( bool reset_callback, bool reset_market_subscriptions )
187 {
188  if ( reset_callback )
189  _subscribe_callback = std::function<void(const fc::variant&)>();
190 
191  if ( reset_market_subscriptions )
192  _market_subscriptions.clear();
193 
194  _notify_remove_create = false;
195  _subscribed_accounts.clear();
196  static fc::bloom_parameters param(10000, 1.0/100, 1024*8*8*2);
198 }
199 
201 // //
202 // Blocks and transactions //
203 // //
205 
206 optional<block_header> database_api::get_block_header(uint32_t block_num)const
207 {
208  return my->get_block_header( block_num );
209 }
210 
211 optional<block_header> database_api_impl::get_block_header(uint32_t block_num) const
212 {
213  auto result = _db.fetch_block_by_number(block_num);
214  if(result)
215  return *result;
216  return {};
217 }
218 map<uint32_t, optional<block_header>> database_api::get_block_header_batch(const vector<uint32_t> block_nums)const
219 {
220  return my->get_block_header_batch( block_nums );
221 }
222 
223 map<uint32_t, optional<block_header>> database_api_impl::get_block_header_batch(
224  const vector<uint32_t> block_nums) const
225 {
226  map<uint32_t, optional<block_header>> results;
227  for (const uint32_t block_num : block_nums)
228  {
229  results[block_num] = get_block_header(block_num);
230  }
231  return results;
232 }
233 
234 optional<signed_block> database_api::get_block(uint32_t block_num)const
235 {
236  return my->get_block( block_num );
237 }
238 
239 optional<signed_block> database_api_impl::get_block(uint32_t block_num)const
240 {
241  return _db.fetch_block_by_number(block_num);
242 }
243 
244 processed_transaction database_api::get_transaction( uint32_t block_num, uint32_t trx_in_block )const
245 {
246  return my->get_transaction( block_num, trx_in_block );
247 }
248 
249 optional<signed_transaction> database_api::get_recent_transaction_by_id( const transaction_id_type& id )const
250 {
251  try {
252  return my->_db.get_recent_transaction( id );
253  } catch ( ... ) {
254  return optional<signed_transaction>();
255  }
256 }
257 
258 processed_transaction database_api_impl::get_transaction(uint32_t block_num, uint32_t trx_num)const
259 {
260  auto opt_block = _db.fetch_block_by_number(block_num);
261  FC_ASSERT( opt_block );
262  FC_ASSERT( opt_block->transactions.size() > trx_num );
263  return opt_block->transactions[trx_num];
264 }
265 
267 // //
268 // Globals //
269 // //
271 
273 {
274  return my->get_chain_properties();
275 }
276 
278 {
279  return _db.get(chain_property_id_type());
280 }
281 
283 {
284  return my->get_global_properties();
285 }
286 
288 {
289  return _db.get(global_property_id_type());
290 }
291 
293 {
294  return my->get_config();
295 }
296 
298 {
300 }
301 
303 {
304  return my->get_chain_id();
305 }
306 
308 {
309  return _db.get_chain_id();
310 }
311 
313 {
314  return my->get_dynamic_global_properties();
315 }
316 
318 {
319  return _db.get(dynamic_global_property_id_type());
320 }
321 
323 // //
324 // Keys //
325 // //
327 
328 vector<flat_set<account_id_type>> database_api::get_key_references( vector<public_key_type> key )const
329 {
330  return my->get_key_references( key );
331 }
332 
336 vector<flat_set<account_id_type>> database_api_impl::get_key_references( vector<public_key_type> keys )const
337 {
338  // api_helper_indexes plugin is required for accessing the secondary index
340  "api_helper_indexes plugin is not enabled on this server." );
341 
342  const auto configured_limit = _app_options->api_limit_get_key_references;
343  FC_ASSERT( keys.size() <= configured_limit,
344  "Number of querying keys can not be greater than ${configured_limit}",
345  ("configured_limit", configured_limit) );
346 
347  const auto& idx = _db.get_index_type<account_index>();
348  const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
349  const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
350 
351  vector< flat_set<account_id_type> > final_result;
352  final_result.reserve(keys.size());
353 
354  for( auto& key : keys )
355  {
356  address a1( pts_address(key, false, 56) );
357  address a2( pts_address(key, true, 56) );
358  address a3( pts_address(key, false, 0) );
359  address a4( pts_address(key, true, 0) );
360  address a5( key );
361 
362  flat_set<account_id_type> result;
363 
364  for( auto& a : {a1,a2,a3,a4,a5} )
365  {
366  auto itr = refs.account_to_address_memberships.find(a);
367  if( itr != refs.account_to_address_memberships.end() )
368  {
369  result.reserve( result.size() + itr->second.size() );
370  for( auto item : itr->second )
371  {
372  result.insert(item);
373  }
374  }
375  }
376 
377  auto itr = refs.account_to_key_memberships.find(key);
378  if( itr != refs.account_to_key_memberships.end() )
379  {
380  result.reserve( result.size() + itr->second.size() );
381  for( auto item : itr->second ) result.insert(item);
382  }
383  final_result.emplace_back( std::move(result) );
384  }
385 
386  return final_result;
387 }
388 
390 {
391  return my->is_public_key_registered(public_key);
392 }
393 
395 {
396  // Short-circuit
397  if (public_key.empty()) {
398  return false;
399  }
400 
401  // Search among all keys using an existing map of *current* account keys
402  public_key_type key;
403  try {
404  key = public_key_type(public_key);
405  } catch ( ... ) {
406  // An invalid public key was detected
407  return false;
408  }
409 
410  // api_helper_indexes plugin is required for accessing the secondary index
412  "api_helper_indexes plugin is not enabled on this server." );
413 
414  const auto& idx = _db.get_index_type<account_index>();
415  const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
416  const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
417  auto itr = refs.account_to_key_memberships.find(key);
418  bool is_known = itr != refs.account_to_key_memberships.end();
419 
420  return is_known;
421 }
422 
424 // //
425 // Accounts //
426 // //
428 
429 account_id_type database_api::get_account_id_from_string(const std::string& name_or_id)const
430 {
431  return my->get_account_from_string( name_or_id )->id;
432 }
433 
434 vector<optional<account_object>> database_api::get_accounts( const vector<std::string>& account_names_or_ids,
435  optional<bool> subscribe )const
436 {
437  return my->get_accounts( account_names_or_ids, subscribe );
438 }
439 
440 vector<optional<account_object>> database_api_impl::get_accounts( const vector<std::string>& account_names_or_ids,
441  optional<bool> subscribe )const
442 {
443  bool to_subscribe = get_whether_to_subscribe( subscribe );
444  vector<optional<account_object>> result; result.reserve(account_names_or_ids.size());
445  std::transform(account_names_or_ids.begin(), account_names_or_ids.end(), std::back_inserter(result),
446  [this,to_subscribe](std::string id_or_name) -> optional<account_object> {
447 
448  const account_object *account = get_account_from_string(id_or_name, false);
449  if(account == nullptr)
450  return {};
451  if( to_subscribe )
452  subscribe_to_item( account->id );
453  return *account;
454  });
455  return result;
456 }
457 
458 std::map<string,full_account> database_api::get_full_accounts( const vector<string>& names_or_ids,
459  optional<bool> subscribe )
460 {
461  return my->get_full_accounts( names_or_ids, subscribe );
462 }
463 
464 std::map<std::string, full_account> database_api_impl::get_full_accounts( const vector<std::string>& names_or_ids,
465  optional<bool> subscribe )
466 {
467  FC_ASSERT( _app_options, "Internal error" );
468  const auto configured_limit = _app_options->api_limit_get_full_accounts;
469  FC_ASSERT( names_or_ids.size() <= configured_limit,
470  "Number of querying accounts can not be greater than ${configured_limit}",
471  ("configured_limit", configured_limit) );
472 
473  bool to_subscribe = get_whether_to_subscribe( subscribe );
474 
475  std::map<std::string, full_account> results;
476 
477  for (const std::string& account_name_or_id : names_or_ids)
478  {
479  const account_object* account = get_account_from_string(account_name_or_id, false);
480  if (account == nullptr)
481  continue;
482 
483  if( to_subscribe )
484  {
485  if(_subscribed_accounts.size() < 100) {
486  _subscribed_accounts.insert( account->get_id() );
487  subscribe_to_item( account->id );
488  }
489  }
490 
491  full_account acnt;
492  acnt.account = *account;
493  acnt.statistics = account->statistics(_db);
494  acnt.registrar_name = account->registrar(_db).name;
495  acnt.referrer_name = account->referrer(_db).name;
496  acnt.lifetime_referrer_name = account->lifetime_referrer(_db).name;
497  acnt.votes = lookup_vote_ids( vector<vote_id_type>( account->options.votes.begin(),
498  account->options.votes.end() ) );
499 
500  if (account->cashback_vb)
501  {
502  acnt.cashback_balance = account->cashback_balance(_db);
503  }
504 
505  size_t api_limit_get_full_accounts_lists = static_cast<size_t>(
507 
508  // Add the account's proposals (if the data is available)
510  {
511  const auto& proposal_idx = _db.get_index_type< primary_index< proposal_index > >();
512  const auto& proposals_by_account = proposal_idx.get_secondary_index<
514 
515  auto required_approvals_itr = proposals_by_account._account_to_proposals.find( account->id );
516  if( required_approvals_itr != proposals_by_account._account_to_proposals.end() )
517  {
518  acnt.proposals.reserve( std::min(required_approvals_itr->second.size(),
519  api_limit_get_full_accounts_lists) );
520  for( auto proposal_id : required_approvals_itr->second )
521  {
522  if(acnt.proposals.size() >= api_limit_get_full_accounts_lists) {
523  acnt.more_data_available.proposals = true;
524  break;
525  }
526  acnt.proposals.push_back(proposal_id(_db));
527  }
528  }
529  }
530 
531  // Add the account's balances
532  const auto& balances = _db.get_index_type< primary_index< account_balance_index > >().
533  get_secondary_index< balances_by_account_index >().get_account_balances( account->id );
534  for( const auto& balance : balances )
535  {
536  if(acnt.balances.size() >= api_limit_get_full_accounts_lists) {
537  acnt.more_data_available.balances = true;
538  break;
539  }
540  acnt.balances.emplace_back(*balance.second);
541  }
542 
543  // Add the account's vesting balances
544  auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>()
545  .equal_range(account->id);
546  for(auto itr = vesting_range.first; itr != vesting_range.second; ++itr)
547  {
548  if(acnt.vesting_balances.size() >= api_limit_get_full_accounts_lists) {
550  break;
551  }
552  acnt.vesting_balances.emplace_back(*itr);
553  }
554 
555  // Add the account's orders
556  auto order_range = _db.get_index_type<limit_order_index>().indices().get<by_account>()
557  .equal_range(account->id);
558  for(auto itr = order_range.first; itr != order_range.second; ++itr)
559  {
560  if(acnt.limit_orders.size() >= api_limit_get_full_accounts_lists) {
561  acnt.more_data_available.limit_orders = true;
562  break;
563  }
564  acnt.limit_orders.emplace_back(*itr);
565  }
566  auto call_range = _db.get_index_type<call_order_index>().indices().get<by_account>().equal_range(account->id);
567  for(auto itr = call_range.first; itr != call_range.second; ++itr)
568  {
569  if(acnt.call_orders.size() >= api_limit_get_full_accounts_lists) {
570  acnt.more_data_available.call_orders = true;
571  break;
572  }
573  acnt.call_orders.emplace_back(*itr);
574  }
575  auto settle_range = _db.get_index_type<force_settlement_index>().indices().get<by_account>()
576  .equal_range(account->id);
577  for(auto itr = settle_range.first; itr != settle_range.second; ++itr)
578  {
579  if(acnt.settle_orders.size() >= api_limit_get_full_accounts_lists) {
581  break;
582  }
583  acnt.settle_orders.emplace_back(*itr);
584  }
585 
586  // get assets issued by user
587  auto asset_range = _db.get_index_type<asset_index>().indices().get<by_issuer>().equal_range(account->id);
588  for(auto itr = asset_range.first; itr != asset_range.second; ++itr)
589  {
590  if(acnt.assets.size() >= api_limit_get_full_accounts_lists) {
591  acnt.more_data_available.assets = true;
592  break;
593  }
594  acnt.assets.emplace_back(itr->id);
595  }
596 
597  // get withdraws permissions
598  auto withdraw_indices = _db.get_index_type<withdraw_permission_index>().indices();
599  auto withdraw_from_range = withdraw_indices.get<by_from>().equal_range(account->id);
600  for(auto itr = withdraw_from_range.first; itr != withdraw_from_range.second; ++itr)
601  {
602  if(acnt.withdraws_from.size() >= api_limit_get_full_accounts_lists) {
604  break;
605  }
606  acnt.withdraws_from.emplace_back(*itr);
607  }
608  auto withdraw_authorized_range = withdraw_indices.get<by_authorized>().equal_range(account->id);
609  for(auto itr = withdraw_authorized_range.first; itr != withdraw_authorized_range.second; ++itr)
610  {
611  if(acnt.withdraws_to.size() >= api_limit_get_full_accounts_lists) {
612  acnt.more_data_available.withdraws_to = true;
613  break;
614  }
615  acnt.withdraws_to.emplace_back(*itr);
616  }
617 
618  // get htlcs
619  auto htlc_from_range = _db.get_index_type<htlc_index>().indices().get<by_from_id>().equal_range(account->id);
620  for(auto itr = htlc_from_range.first; itr != htlc_from_range.second; ++itr)
621  {
622  if(acnt.htlcs_from.size() >= api_limit_get_full_accounts_lists) {
623  acnt.more_data_available.htlcs_from = true;
624  break;
625  }
626  acnt.htlcs_from.emplace_back(*itr);
627  }
628  auto htlc_to_range = _db.get_index_type<htlc_index>().indices().get<by_to_id>().equal_range(account->id);
629  for(auto itr = htlc_to_range.first; itr != htlc_to_range.second; ++itr)
630  {
631  if(acnt.htlcs_to.size() >= api_limit_get_full_accounts_lists) {
632  acnt.more_data_available.htlcs_to = true;
633  break;
634  }
635  acnt.htlcs_to.emplace_back(*itr);
636  }
637 
638  results[account_name_or_id] = acnt;
639  }
640  return results;
641 }
642 
643 optional<account_object> database_api::get_account_by_name( string name )const
644 {
645  return my->get_account_by_name( name );
646 }
647 
648 optional<account_object> database_api_impl::get_account_by_name( string name )const
649 {
650  const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
651  auto itr = idx.find(name);
652  if (itr != idx.end())
653  return *itr;
654  return optional<account_object>();
655 }
656 
657 vector<account_id_type> database_api::get_account_references( const std::string account_id_or_name )const
658 {
659  return my->get_account_references( account_id_or_name );
660 }
661 
662 vector<account_id_type> database_api_impl::get_account_references( const std::string account_id_or_name )const
663 {
664  // api_helper_indexes plugin is required for accessing the secondary index
666  "api_helper_indexes plugin is not enabled on this server." );
667 
668  const auto& idx = _db.get_index_type<account_index>();
669  const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
670  const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
671  const account_id_type account_id = get_account_from_string(account_id_or_name)->id;
672  auto itr = refs.account_to_account_memberships.find(account_id);
673  vector<account_id_type> result;
674 
675  if( itr != refs.account_to_account_memberships.end() )
676  {
677  result.reserve( itr->second.size() );
678  for( auto item : itr->second ) result.push_back(item);
679  }
680  return result;
681 }
682 
683 vector<optional<account_object>> database_api::lookup_account_names(const vector<string>& account_names)const
684 {
685  return my->lookup_account_names( account_names );
686 }
687 
688 vector<optional<account_object>> database_api_impl::lookup_account_names(const vector<string>& account_names)const
689 {
690  const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
691  vector<optional<account_object> > result;
692  result.reserve(account_names.size());
693  std::transform(account_names.begin(), account_names.end(), std::back_inserter(result),
694  [&accounts_by_name](const string& name) -> optional<account_object> {
695  auto itr = accounts_by_name.find(name);
696  return itr == accounts_by_name.end()? optional<account_object>() : *itr;
697  });
698  return result;
699 }
700 
701 map<string,account_id_type> database_api::lookup_accounts( const string& lower_bound_name,
702  uint32_t limit,
703  optional<bool> subscribe )const
704 {
705  return my->lookup_accounts( lower_bound_name, limit, subscribe );
706 }
707 
708 map<string,account_id_type> database_api_impl::lookup_accounts( const string& lower_bound_name,
709  uint32_t limit,
710  optional<bool> subscribe )const
711 {
712  FC_ASSERT( _app_options, "Internal error" );
713  const auto configured_limit = _app_options->api_limit_lookup_accounts;
714  FC_ASSERT( limit <= configured_limit,
715  "limit can not be greater than ${configured_limit}",
716  ("configured_limit", configured_limit) );
717 
718  const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
719  map<string,account_id_type> result;
720 
721  if( limit == 0 ) // shortcut to save a database query
722  return result;
723  // In addition to the common auto-subscription rules, here we auto-subscribe if only look for one account
724  bool to_subscribe = (limit == 1 && get_whether_to_subscribe( subscribe ));
725  for( auto itr = accounts_by_name.lower_bound(lower_bound_name);
726  limit-- && itr != accounts_by_name.end();
727  ++itr )
728  {
729  result.insert(make_pair(itr->name, itr->get_id()));
730  if( to_subscribe )
731  subscribe_to_item( itr->id );
732  }
733 
734  return result;
735 }
736 
738 {
739  return my->get_account_count();
740 }
741 
743 {
744  return _db.get_index_type<account_index>().indices().size();
745 }
746 
748 // //
749 // Balances //
750 // //
752 
753 vector<asset> database_api::get_account_balances( const std::string& account_name_or_id,
754  const flat_set<asset_id_type>& assets )const
755 {
756  return my->get_account_balances( account_name_or_id, assets );
757 }
758 
759 vector<asset> database_api_impl::get_account_balances( const std::string& account_name_or_id,
760  const flat_set<asset_id_type>& assets )const
761 {
762  const account_object* account = get_account_from_string(account_name_or_id);
763  account_id_type acnt = account->id;
764  vector<asset> result;
765  if (assets.empty())
766  {
767  // if the caller passes in an empty list of assets, return balances for all assets the account owns
769  const auto& balances = balance_index.get_secondary_index< balances_by_account_index >()
770  .get_account_balances( acnt );
771  for( const auto& balance : balances )
772  result.push_back( balance.second->get_balance() );
773  }
774  else
775  {
776  result.reserve(assets.size());
777 
778  std::transform(assets.begin(), assets.end(), std::back_inserter(result),
779  [this, acnt](asset_id_type id) { return _db.get_balance(acnt, id); });
780  }
781 
782  return result;
783 }
784 
785 vector<asset> database_api::get_named_account_balances( const std::string& name,
786  const flat_set<asset_id_type>& assets )const
787 {
788  return my->get_account_balances( name, assets );
789 }
790 
791 vector<balance_object> database_api::get_balance_objects( const vector<address>& addrs )const
792 {
793  return my->get_balance_objects( addrs );
794 }
795 
796 vector<balance_object> database_api_impl::get_balance_objects( const vector<address>& addrs )const
797 {
798  try
799  {
800  const auto& bal_idx = _db.get_index_type<balance_index>();
801  const auto& by_owner_idx = bal_idx.indices().get<by_owner>();
802 
803  vector<balance_object> result;
804 
805  for( const auto& owner : addrs )
806  {
807  auto itr = by_owner_idx.lower_bound( boost::make_tuple( owner, asset_id_type(0) ) );
808  while( itr != by_owner_idx.end() && itr->owner == owner )
809  {
810  result.push_back( *itr );
811  ++itr;
812  }
813  }
814  return result;
815  }
816  FC_CAPTURE_AND_RETHROW( (addrs) )
817 }
818 
819 vector<asset> database_api::get_vested_balances( const vector<balance_id_type>& objs )const
820 {
821  return my->get_vested_balances( objs );
822 }
823 
824 vector<asset> database_api_impl::get_vested_balances( const vector<balance_id_type>& objs )const
825 {
826  try
827  {
828  vector<asset> result;
829  result.reserve( objs.size() );
830  auto now = _db.head_block_time();
831  for( auto obj : objs )
832  result.push_back( obj(_db).available( now ) );
833  return result;
834  } FC_CAPTURE_AND_RETHROW( (objs) )
835 }
836 
837 vector<vesting_balance_object> database_api::get_vesting_balances( const std::string account_id_or_name )const
838 {
839  return my->get_vesting_balances( account_id_or_name );
840 }
841 
842 vector<vesting_balance_object> database_api_impl::get_vesting_balances( const std::string account_id_or_name )const
843 {
844  try
845  {
846  const account_id_type account_id = get_account_from_string(account_id_or_name)->id;
847  vector<vesting_balance_object> result;
848  auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>()
849  .equal_range(account_id);
850  std::for_each(vesting_range.first, vesting_range.second,
851  [&result](const vesting_balance_object& balance) {
852  result.emplace_back(balance);
853  });
854  return result;
855  }
856  FC_CAPTURE_AND_RETHROW( (account_id_or_name) );
857 }
858 
860 // //
861 // Assets //
862 // //
864 
865 asset_id_type database_api::get_asset_id_from_string(const std::string& symbol_or_id)const
866 {
867  return my->get_asset_from_string( symbol_or_id )->id;
868 }
869 
870 vector<optional<extended_asset_object>> database_api::get_assets(
871  const vector<std::string>& asset_symbols_or_ids,
872  optional<bool> subscribe )const
873 {
874  return my->get_assets( asset_symbols_or_ids, subscribe );
875 }
876 
877 vector<optional<extended_asset_object>> database_api_impl::get_assets(
878  const vector<std::string>& asset_symbols_or_ids,
879  optional<bool> subscribe )const
880 {
881  bool to_subscribe = get_whether_to_subscribe( subscribe );
882  vector<optional<extended_asset_object>> result; result.reserve(asset_symbols_or_ids.size());
883  std::transform(asset_symbols_or_ids.begin(), asset_symbols_or_ids.end(), std::back_inserter(result),
884  [this,to_subscribe](std::string id_or_name) -> optional<extended_asset_object> {
885 
886  const asset_object* asset_obj = get_asset_from_string( id_or_name, false );
887  if( asset_obj == nullptr )
888  return {};
889  if( to_subscribe )
890  subscribe_to_item( asset_obj->id );
891  return extend_asset( *asset_obj );
892  });
893  return result;
894 }
895 
896 vector<extended_asset_object> database_api::list_assets(const string& lower_bound_symbol, uint32_t limit)const
897 {
898  return my->list_assets( lower_bound_symbol, limit );
899 }
900 
901 vector<extended_asset_object> database_api_impl::list_assets(const string& lower_bound_symbol, uint32_t limit)const
902 {
903  FC_ASSERT( _app_options, "Internal error" );
904  const auto configured_limit = _app_options->api_limit_get_assets;
905  FC_ASSERT( limit <= configured_limit,
906  "limit can not be greater than ${configured_limit}",
907  ("configured_limit", configured_limit) );
908 
909  const auto& assets_by_symbol = _db.get_index_type<asset_index>().indices().get<by_symbol>();
910  vector<extended_asset_object> result;
911  result.reserve(limit);
912 
913  auto itr = assets_by_symbol.lower_bound(lower_bound_symbol);
914 
915  if( lower_bound_symbol == "" )
916  itr = assets_by_symbol.begin();
917 
918  while(limit-- && itr != assets_by_symbol.end())
919  result.emplace_back( extend_asset( *itr++ ) );
920 
921  return result;
922 }
923 
925 {
926  return my->get_asset_count();
927 }
928 
930 {
931  return _db.get_index_type<asset_index>().indices().size();
932 }
933 
934 vector<extended_asset_object> database_api::get_assets_by_issuer(const std::string& issuer_name_or_id,
935  asset_id_type start, uint32_t limit)const
936 {
937  return my->get_assets_by_issuer(issuer_name_or_id, start, limit);
938 }
939 
940 vector<extended_asset_object> database_api_impl::get_assets_by_issuer(const std::string& issuer_name_or_id,
941  asset_id_type start, uint32_t limit)const
942 {
943  FC_ASSERT( _app_options, "Internal error" );
944  const auto configured_limit = _app_options->api_limit_get_assets;
945  FC_ASSERT( limit <= configured_limit,
946  "limit can not be greater than ${configured_limit}",
947  ("configured_limit", configured_limit) );
948 
949  vector<extended_asset_object> result;
950  const account_id_type account = get_account_from_string(issuer_name_or_id)->id;
951  const auto& asset_idx = _db.get_index_type<asset_index>().indices().get<by_issuer>();
952  auto asset_index_end = asset_idx.end();
953  auto asset_itr = asset_idx.lower_bound(boost::make_tuple(account, start));
954  while(asset_itr != asset_index_end && asset_itr->issuer == account && result.size() < limit)
955  {
956  result.emplace_back( extend_asset( *asset_itr ) );
957  ++asset_itr;
958  }
959  return result;
960 }
961 
962 vector<optional<extended_asset_object>> database_api::lookup_asset_symbols(
963  const vector<string>& symbols_or_ids )const
964 {
965  return my->lookup_asset_symbols( symbols_or_ids );
966 }
967 
968 vector<optional<extended_asset_object>> database_api_impl::lookup_asset_symbols(
969  const vector<string>& symbols_or_ids )const
970 {
971  const auto& assets_by_symbol = _db.get_index_type<asset_index>().indices().get<by_symbol>();
972  vector<optional<extended_asset_object> > result;
973  result.reserve(symbols_or_ids.size());
974  std::transform(symbols_or_ids.begin(), symbols_or_ids.end(), std::back_inserter(result),
975  [this, &assets_by_symbol](const string& symbol_or_id) -> optional<extended_asset_object> {
976  if( !symbol_or_id.empty() && std::isdigit(symbol_or_id[0]) )
977  {
978  auto ptr = _db.find(variant(symbol_or_id, 1).as<asset_id_type>(1));
979  return ptr == nullptr? optional<extended_asset_object>() : extend_asset( *ptr );
980  }
981  auto itr = assets_by_symbol.find(symbol_or_id);
982  return itr == assets_by_symbol.end()? optional<extended_asset_object>() : extend_asset( *itr );
983  });
984  return result;
985 }
986 
988 // //
989 // Markets / feeds //
990 // //
992 
993 vector<limit_order_object> database_api::get_limit_orders(std::string a, std::string b, uint32_t limit)const
994 {
995  return my->get_limit_orders( a, b, limit );
996 }
997 
998 vector<limit_order_object> database_api_impl::get_limit_orders( const std::string& a, const std::string& b,
999  uint32_t limit )const
1000 {
1001  FC_ASSERT( _app_options, "Internal error" );
1002  const auto configured_limit = _app_options->api_limit_get_limit_orders;
1003  FC_ASSERT( limit <= configured_limit,
1004  "limit can not be greater than ${configured_limit}",
1005  ("configured_limit", configured_limit) );
1006 
1007  const asset_id_type asset_a_id = get_asset_from_string(a)->id;
1008  const asset_id_type asset_b_id = get_asset_from_string(b)->id;
1009 
1010  return get_limit_orders(asset_a_id, asset_b_id, limit);
1011 }
1012 
1013 vector<limit_order_object> database_api::get_limit_orders_by_account( const string& account_name_or_id,
1014  optional<uint32_t> limit, optional<limit_order_id_type> start_id )
1015 {
1016  return my->get_limit_orders_by_account( account_name_or_id, limit, start_id );
1017 }
1018 
1019 vector<limit_order_object> database_api_impl::get_limit_orders_by_account( const string& account_name_or_id,
1020  optional<uint32_t> olimit, optional<limit_order_id_type> ostart_id )
1021 {
1022  uint32_t limit = olimit.valid() ? *olimit : 101;
1023 
1024  FC_ASSERT( _app_options, "Internal error" );
1025  const auto configured_limit = _app_options->api_limit_get_limit_orders_by_account;
1026  FC_ASSERT( limit <= configured_limit,
1027  "limit can not be greater than ${configured_limit}",
1028  ("configured_limit", configured_limit) );
1029 
1030  vector<limit_order_object> results;
1031 
1032  const account_object* account = get_account_from_string(account_name_or_id);
1033  if (account == nullptr)
1034  return results;
1035 
1036  limit_order_id_type start_id = ostart_id.valid() ? *ostart_id : limit_order_id_type();
1037 
1038  const auto& index_by_account = _db.get_index_type<limit_order_index>().indices().get<by_account>();
1039  auto lower_itr = index_by_account.lower_bound( std::make_tuple( account->id, start_id ) );
1040  auto upper_itr = index_by_account.upper_bound( account->id );
1041 
1042  results.reserve( limit );
1043  uint32_t count = 0;
1044  for ( ; lower_itr != upper_itr && count < limit; ++lower_itr, ++count)
1045  {
1046  const limit_order_object &order = *lower_itr;
1047  results.emplace_back(order);
1048  }
1049 
1050  return results;
1051 }
1052 
1053 vector<limit_order_object> database_api::get_account_limit_orders(
1054  const string& account_name_or_id, const string &base, const string &quote,
1055  uint32_t limit, optional<limit_order_id_type> ostart_id, optional<price> ostart_price )
1056 {
1057  return my->get_account_limit_orders( account_name_or_id, base, quote, limit, ostart_id, ostart_price );
1058 }
1059 
1061  const string& account_name_or_id, const string &base, const string &quote,
1062  uint32_t limit, optional<limit_order_id_type> ostart_id, optional<price> ostart_price )
1063 {
1064  FC_ASSERT( _app_options, "Internal error" );
1065  const auto configured_limit = _app_options->api_limit_get_account_limit_orders;
1066  FC_ASSERT( limit <= configured_limit,
1067  "limit can not be greater than ${configured_limit}",
1068  ("configured_limit", configured_limit) );
1069 
1070  vector<limit_order_object> results;
1071  uint32_t count = 0;
1072 
1073  const account_object* account = get_account_from_string(account_name_or_id);
1074  if (account == nullptr)
1075  return results;
1076 
1077  auto assets = lookup_asset_symbols( {base, quote} );
1078  FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
1079  FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
1080 
1081  auto base_id = assets[0]->id;
1082  auto quote_id = assets[1]->id;
1083 
1084  if (ostart_price.valid()) {
1085  FC_ASSERT(ostart_price->base.asset_id == base_id, "Base asset inconsistent with start price");
1086  FC_ASSERT(ostart_price->quote.asset_id == quote_id, "Quote asset inconsistent with start price");
1087  }
1088 
1089  const auto& index_by_account = _db.get_index_type<limit_order_index>().indices().get<by_account_price>();
1090  limit_order_multi_index_type::index<by_account_price>::type::const_iterator lower_itr;
1091  limit_order_multi_index_type::index<by_account_price>::type::const_iterator upper_itr;
1092 
1093  // if both order_id and price are invalid, query the first page
1094  if ( !ostart_id.valid() && !ostart_price.valid() )
1095  {
1096  lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, price::max(base_id, quote_id)));
1097  }
1098  else if ( ostart_id.valid() )
1099  {
1100  // in case of the order been deleted during page querying
1101  const limit_order_object *p_loo = _db.find(*ostart_id);
1102 
1103  if ( !p_loo )
1104  {
1105  if ( ostart_price.valid() )
1106  {
1107  lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, *ostart_price, *ostart_id));
1108  }
1109  else
1110  {
1111  // start order id been deleted, yet not provided price either
1112  FC_THROW("Order id invalid (maybe just been canceled?), and start price not provided");
1113  }
1114  }
1115  else
1116  {
1117  const limit_order_object &loo = *p_loo;
1118 
1119  // in case of the order not belongs to specified account or market
1120  FC_ASSERT(loo.sell_price.base.asset_id == base_id, "Order base asset inconsistent");
1121  FC_ASSERT(loo.sell_price.quote.asset_id == quote_id, "Order quote asset inconsistent with order");
1122  FC_ASSERT(loo.seller == account->get_id(), "Order not owned by specified account");
1123 
1124  lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, loo.sell_price, *ostart_id));
1125  }
1126  }
1127  else
1128  {
1129  // if reach here start_price must be valid
1130  lower_itr = index_by_account.lower_bound(std::make_tuple(account->id, *ostart_price));
1131  }
1132 
1133  upper_itr = index_by_account.upper_bound(std::make_tuple(account->id, price::min(base_id, quote_id)));
1134 
1135  // Add the account's orders
1136  for ( ; lower_itr != upper_itr && count < limit; ++lower_itr, ++count)
1137  {
1138  const limit_order_object &order = *lower_itr;
1139  results.emplace_back(order);
1140  }
1141 
1142  return results;
1143 }
1144 
1145 vector<call_order_object> database_api::get_call_orders(const std::string& a, uint32_t limit)const
1146 {
1147  return my->get_call_orders( a, limit );
1148 }
1149 
1150 vector<call_order_object> database_api_impl::get_call_orders(const std::string& a, uint32_t limit)const
1151 {
1152  FC_ASSERT( _app_options, "Internal error" );
1153  const auto configured_limit = _app_options->api_limit_get_call_orders;
1154  FC_ASSERT( limit <= configured_limit,
1155  "limit can not be greater than ${configured_limit}",
1156  ("configured_limit", configured_limit) );
1157 
1158  const asset_object* mia = get_asset_from_string(a);
1159  const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_collateral>();
1160  price index_price = price::min( mia->bitasset_data(_db).options.short_backing_asset, mia->get_id() );
1161 
1162  vector< call_order_object> result;
1163  auto itr_min = call_index.lower_bound(index_price);
1164  auto itr_max = call_index.upper_bound(index_price.max());
1165  while( itr_min != itr_max && result.size() < limit )
1166  {
1167  result.emplace_back(*itr_min);
1168  ++itr_min;
1169  }
1170  return result;
1171 }
1172 
1173 vector<call_order_object> database_api::get_call_orders_by_account(const std::string& account_name_or_id,
1174  asset_id_type start, uint32_t limit)const
1175 {
1176  return my->get_call_orders_by_account( account_name_or_id, start, limit );
1177 }
1178 
1179 vector<call_order_object> database_api_impl::get_call_orders_by_account(const std::string& account_name_or_id,
1180  asset_id_type start, uint32_t limit)const
1181 {
1182  FC_ASSERT( _app_options, "Internal error" );
1183  const auto configured_limit = _app_options->api_limit_get_call_orders;
1184  FC_ASSERT( limit <= configured_limit,
1185  "limit can not be greater than ${configured_limit}",
1186  ("configured_limit", configured_limit) );
1187 
1188  vector<call_order_object> result;
1189  const account_id_type account = get_account_from_string(account_name_or_id)->id;
1190  const auto& call_idx = _db.get_index_type<call_order_index>().indices().get<by_account>();
1191  auto call_index_end = call_idx.end();
1192  auto call_itr = call_idx.lower_bound(boost::make_tuple(account, start));
1193  while(call_itr != call_index_end && call_itr->borrower == account && result.size() < limit)
1194  {
1195  result.push_back(*call_itr);
1196  ++call_itr;
1197  }
1198  return result;
1199 }
1200 
1201 vector<force_settlement_object> database_api::get_settle_orders(const std::string& a, uint32_t limit)const
1202 {
1203  return my->get_settle_orders( a, limit );
1204 }
1205 
1206 vector<force_settlement_object> database_api_impl::get_settle_orders(const std::string& a, uint32_t limit)const
1207 {
1208  FC_ASSERT( _app_options, "Internal error" );
1209  const auto configured_limit = _app_options->api_limit_get_settle_orders;
1210  FC_ASSERT( limit <= configured_limit,
1211  "limit can not be greater than ${configured_limit}",
1212  ("configured_limit", configured_limit) );
1213 
1214  const asset_id_type asset_a_id = get_asset_from_string(a)->id;
1215  const auto& settle_index = _db.get_index_type<force_settlement_index>().indices().get<by_expiration>();
1216  const asset_object& mia = _db.get(asset_a_id);
1217 
1218  vector<force_settlement_object> result;
1219  auto itr_min = settle_index.lower_bound(mia.get_id());
1220  auto itr_max = settle_index.upper_bound(mia.get_id());
1221  while( itr_min != itr_max && result.size() < limit )
1222  {
1223  result.emplace_back(*itr_min);
1224  ++itr_min;
1225  }
1226  return result;
1227 }
1228 
1229 vector<force_settlement_object> database_api::get_settle_orders_by_account(
1230  const std::string& account_name_or_id,
1231  force_settlement_id_type start,
1232  uint32_t limit )const
1233 {
1234  return my->get_settle_orders_by_account( account_name_or_id, start, limit);
1235 }
1236 
1237 vector<force_settlement_object> database_api_impl::get_settle_orders_by_account(
1238  const std::string& account_name_or_id,
1239  force_settlement_id_type start,
1240  uint32_t limit )const
1241 {
1242  FC_ASSERT( _app_options, "Internal error" );
1243  const auto configured_limit = _app_options->api_limit_get_settle_orders;
1244  FC_ASSERT( limit <= configured_limit,
1245  "limit can not be greater than ${configured_limit}",
1246  ("configured_limit", configured_limit) );
1247 
1248  vector<force_settlement_object> result;
1249  const account_id_type account = get_account_from_string(account_name_or_id)->id;
1250  const auto& settle_idx = _db.get_index_type<force_settlement_index>().indices().get<by_account>();
1251  auto settle_index_end = settle_idx.end();
1252  auto settle_itr = settle_idx.lower_bound(boost::make_tuple(account, start));
1253  while(settle_itr != settle_index_end && settle_itr->owner == account && result.size() < limit)
1254  {
1255  result.push_back(*settle_itr);
1256  ++settle_itr;
1257  }
1258  return result;
1259 }
1260 
1261 
1262 vector<call_order_object> database_api::get_margin_positions( const std::string account_id_or_name )const
1263 {
1264  return my->get_margin_positions( account_id_or_name );
1265 }
1266 
1267 vector<call_order_object> database_api_impl::get_margin_positions( const std::string account_id_or_name )const
1268 {
1269  try
1270  {
1271  const auto& idx = _db.get_index_type<call_order_index>();
1272  const auto& aidx = idx.indices().get<by_account>();
1273  const account_id_type id = get_account_from_string(account_id_or_name)->id;
1274  auto start = aidx.lower_bound( boost::make_tuple( id, asset_id_type(0) ) );
1275  auto end = aidx.lower_bound( boost::make_tuple( id+1, asset_id_type(0) ) );
1276  vector<call_order_object> result;
1277  while( start != end )
1278  {
1279  result.push_back(*start);
1280  ++start;
1281  }
1282  return result;
1283  } FC_CAPTURE_AND_RETHROW( (account_id_or_name) )
1284 }
1285 
1286 vector<collateral_bid_object> database_api::get_collateral_bids( const std::string& asset,
1287  uint32_t limit, uint32_t start )const
1288 {
1289  return my->get_collateral_bids( asset, limit, start );
1290 }
1291 
1292 vector<collateral_bid_object> database_api_impl::get_collateral_bids( const std::string& asset,
1293  uint32_t limit, uint32_t skip )const
1294 { try {
1295  FC_ASSERT( _app_options, "Internal error" );
1296  const auto configured_limit = _app_options->api_limit_get_collateral_bids;
1297  FC_ASSERT( limit <= configured_limit,
1298  "limit can not be greater than ${configured_limit}",
1299  ("configured_limit", configured_limit) );
1300 
1301  const asset_id_type asset_id = get_asset_from_string(asset)->id;
1302  const asset_object& swan = asset_id(_db);
1303  FC_ASSERT( swan.is_market_issued() );
1304  const asset_bitasset_data_object& bad = swan.bitasset_data(_db);
1305  const asset_object& back = bad.options.short_backing_asset(_db);
1306  const auto& idx = _db.get_index_type<collateral_bid_index>();
1307  const auto& aidx = idx.indices().get<by_price>();
1308  auto start = aidx.lower_bound( boost::make_tuple( asset_id,
1309  price::max(back.id, asset_id),
1310  collateral_bid_id_type() ) );
1311  auto end = aidx.lower_bound( boost::make_tuple( asset_id,
1312  price::min(back.id, asset_id),
1313  collateral_bid_id_type(GRAPHENE_DB_MAX_INSTANCE_ID) ) );
1314  vector<collateral_bid_object> result;
1315  while( skip-- > 0 && start != end ) { ++start; }
1316  while( start != end && limit-- > 0)
1317  {
1318  result.push_back(*start);
1319  ++start;
1320  }
1321  return result;
1322 } FC_CAPTURE_AND_RETHROW( (asset)(limit)(skip) ) }
1323 
1324 void database_api::subscribe_to_market( std::function<void(const variant&)> callback,
1325  const std::string& a, const std::string& b )
1326 {
1327  my->subscribe_to_market( callback, a, b );
1328 }
1329 
1330 void database_api_impl::subscribe_to_market( std::function<void(const variant&)> callback,
1331  const std::string& a, const std::string& b )
1332 {
1333  auto asset_a_id = get_asset_from_string(a)->id;
1334  auto asset_b_id = get_asset_from_string(b)->id;
1335 
1336  if(asset_a_id > asset_b_id) std::swap(asset_a_id,asset_b_id);
1337  FC_ASSERT(asset_a_id != asset_b_id);
1338  _market_subscriptions[ std::make_pair(asset_a_id,asset_b_id) ] = callback;
1339 }
1340 
1341 void database_api::unsubscribe_from_market(const std::string& a, const std::string& b)
1342 {
1343  my->unsubscribe_from_market( a, b );
1344 }
1345 
1346 void database_api_impl::unsubscribe_from_market(const std::string& a, const std::string& b)
1347 {
1348  auto asset_a_id = get_asset_from_string(a)->id;
1349  auto asset_b_id = get_asset_from_string(b)->id;
1350 
1351  if(a > b) std::swap(asset_a_id,asset_b_id);
1352  FC_ASSERT(asset_a_id != asset_b_id);
1353  _market_subscriptions.erase(std::make_pair(asset_a_id,asset_b_id));
1354 }
1355 
1356 market_ticker database_api::get_ticker( const string& base, const string& quote )const
1357 {
1358  return my->get_ticker( base, quote );
1359 }
1360 
1361 market_ticker database_api_impl::get_ticker( const string& base, const string& quote, bool skip_order_book )const
1362 {
1363  FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." );
1364 
1365  const auto assets = lookup_asset_symbols( {base, quote} );
1366 
1367  FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
1368  FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
1369 
1370  auto base_id = assets[0]->id;
1371  auto quote_id = assets[1]->id;
1372  if( base_id > quote_id ) std::swap( base_id, quote_id );
1373  const auto& ticker_idx = _db.get_index_type<market_ticker_index>().indices().get<by_market>();
1374  auto itr = ticker_idx.find( std::make_tuple( base_id, quote_id ) );
1375  const fc::time_point_sec now = _db.head_block_time();
1376  if( itr != ticker_idx.end() )
1377  {
1378  order_book orders;
1379  if (!skip_order_book)
1380  {
1381  orders = get_order_book(assets[0]->symbol, assets[1]->symbol, 1);
1382  }
1383  return market_ticker(*itr, now, *assets[0], *assets[1], orders);
1384  }
1385  // if no ticker is found for this market we return an empty ticker
1386  market_ticker empty_result(now, *assets[0], *assets[1]);
1387  return empty_result;
1388 }
1389 
1390 market_volume database_api::get_24_volume( const string& base, const string& quote )const
1391 {
1392  return my->get_24_volume( base, quote );
1393 }
1394 
1395 market_volume database_api_impl::get_24_volume( const string& base, const string& quote )const
1396 {
1397  const auto& ticker = get_ticker( base, quote, true );
1398 
1399  market_volume result;
1400  result.time = ticker.time;
1401  result.base = ticker.base;
1402  result.quote = ticker.quote;
1403  result.base_volume = ticker.base_volume;
1404  result.quote_volume = ticker.quote_volume;
1405 
1406  return result;
1407 }
1408 
1409 order_book database_api::get_order_book( const string& base, const string& quote, unsigned limit )const
1410 {
1411  return my->get_order_book( base, quote, limit);
1412 }
1413 
1414 order_book database_api_impl::get_order_book( const string& base, const string& quote, unsigned limit )const
1415 {
1416  FC_ASSERT( _app_options, "Internal error" );
1417  const auto configured_limit = _app_options->api_limit_get_order_book;
1418  FC_ASSERT( limit <= configured_limit,
1419  "limit can not be greater than ${configured_limit}",
1420  ("configured_limit", configured_limit) );
1421 
1422  order_book result;
1423  result.base = base;
1424  result.quote = quote;
1425 
1426  auto assets = lookup_asset_symbols( {base, quote} );
1427  FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
1428  FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
1429 
1430  auto base_id = assets[0]->id;
1431  auto quote_id = assets[1]->id;
1432  auto orders = get_limit_orders( base_id, quote_id, limit );
1433 
1434  for( const auto& o : orders )
1435  {
1436  if( o.sell_price.base.asset_id == base_id )
1437  {
1438  order ord;
1439  ord.price = price_to_string( o.sell_price, *assets[0], *assets[1] );
1440  ord.quote = assets[1]->amount_to_string( share_type( fc::uint128_t( o.for_sale.value )
1441  * o.sell_price.quote.amount.value
1442  / o.sell_price.base.amount.value ) );
1443  ord.base = assets[0]->amount_to_string( o.for_sale );
1444  result.bids.push_back( ord );
1445  }
1446  else
1447  {
1448  order ord;
1449  ord.price = price_to_string( o.sell_price, *assets[0], *assets[1] );
1450  ord.quote = assets[1]->amount_to_string( o.for_sale );
1451  ord.base = assets[0]->amount_to_string( share_type( fc::uint128_t( o.for_sale.value )
1452  * o.sell_price.quote.amount.value
1453  / o.sell_price.base.amount.value ) );
1454  result.asks.push_back( ord );
1455  }
1456  }
1457 
1458  return result;
1459 }
1460 
1461 vector<market_ticker> database_api::get_top_markets(uint32_t limit)const
1462 {
1463  return my->get_top_markets(limit);
1464 }
1465 
1466 vector<market_ticker> database_api_impl::get_top_markets(uint32_t limit)const
1467 {
1468  FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." );
1469 
1470  const auto configured_limit = _app_options->api_limit_get_top_markets;
1471  FC_ASSERT( limit <= configured_limit,
1472  "limit can not be greater than ${configured_limit}",
1473  ("configured_limit", configured_limit) );
1474 
1475  const auto& volume_idx = _db.get_index_type<market_ticker_index>().indices().get<by_volume>();
1476  auto itr = volume_idx.rbegin();
1477  vector<market_ticker> result;
1478  result.reserve(limit);
1479  const fc::time_point_sec now = _db.head_block_time();
1480 
1481  while( itr != volume_idx.rend() && result.size() < limit)
1482  {
1483  const asset_object base = itr->base(_db);
1484  const asset_object quote = itr->quote(_db);
1485  order_book orders;
1486  orders = get_order_book(base.symbol, quote.symbol, 1);
1487 
1488  result.emplace_back(market_ticker(*itr, now, base, quote, orders));
1489  ++itr;
1490  }
1491  return result;
1492 }
1493 
1494 vector<market_trade> database_api::get_trade_history( const string& base,
1495  const string& quote,
1496  fc::time_point_sec start,
1497  fc::time_point_sec stop,
1498  unsigned limit )const
1499 {
1500  return my->get_trade_history( base, quote, start, stop, limit );
1501 }
1502 
1503 vector<market_trade> database_api_impl::get_trade_history( const string& base,
1504  const string& quote,
1505  fc::time_point_sec start,
1506  fc::time_point_sec stop,
1507  unsigned limit )const
1508 {
1509  FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." );
1510 
1511  const auto configured_limit = _app_options->api_limit_get_trade_history;
1512  FC_ASSERT( limit <= configured_limit,
1513  "limit can not be greater than ${configured_limit}",
1514  ("configured_limit", configured_limit) );
1515 
1516  auto assets = lookup_asset_symbols( {base, quote} );
1517  FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
1518  FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
1519 
1520  auto base_id = assets[0]->id;
1521  auto quote_id = assets[1]->id;
1522 
1523  if( base_id > quote_id ) std::swap( base_id, quote_id );
1524 
1525  if ( start.sec_since_epoch() == 0 )
1527 
1528  uint32_t count = 0;
1529  const auto& history_idx = _db.get_index_type<market_history::history_index>().indices().get<by_market_time>();
1530  auto itr = history_idx.lower_bound( std::make_tuple( base_id, quote_id, start ) );
1531  vector<market_trade> result;
1532 
1533  while( itr != history_idx.end() && count < limit
1534  && !( itr->key.base != base_id || itr->key.quote != quote_id || itr->time < stop ) )
1535  {
1536  {
1537  market_trade trade;
1538 
1539  if( assets[0]->id == itr->op.receives.asset_id )
1540  {
1541  trade.amount = assets[1]->amount_to_string( itr->op.pays );
1542  trade.value = assets[0]->amount_to_string( itr->op.receives );
1543  }
1544  else
1545  {
1546  trade.amount = assets[1]->amount_to_string( itr->op.receives );
1547  trade.value = assets[0]->amount_to_string( itr->op.pays );
1548  }
1549 
1550  trade.date = itr->time;
1551  trade.price = price_to_string( itr->op.fill_price, *assets[0], *assets[1] );
1552 
1553  if( itr->op.is_maker )
1554  {
1555  trade.sequence = -itr->key.sequence;
1556  trade.side1_account_id = itr->op.account_id;
1557  if(itr->op.receives.asset_id == assets[0]->id)
1558  trade.type = "sell";
1559  else
1560  trade.type = "buy";
1561  }
1562  else
1563  trade.side2_account_id = itr->op.account_id;
1564 
1565  auto next_itr = std::next(itr);
1566  // Trades are usually tracked in each direction, exception: for global settlement only one side is recorded
1567  if( next_itr != history_idx.end() && next_itr->key.base == base_id && next_itr->key.quote == quote_id
1568  && next_itr->time == itr->time && next_itr->op.is_maker != itr->op.is_maker )
1569  { // next_itr now could be the other direction // FIXME not 100% sure
1570  if( next_itr->op.is_maker )
1571  {
1572  trade.sequence = -next_itr->key.sequence;
1573  trade.side1_account_id = next_itr->op.account_id;
1574  if(next_itr->op.receives.asset_id == assets[0]->id)
1575  trade.type = "sell";
1576  else
1577  trade.type = "buy";
1578  }
1579  else
1580  trade.side2_account_id = next_itr->op.account_id;
1581  // skip the other direction
1582  itr = next_itr;
1583  }
1584 
1585  result.push_back( trade );
1586  ++count;
1587  }
1588 
1589  ++itr;
1590  }
1591 
1592  return result;
1593 }
1594 
1596  const string& base,
1597  const string& quote,
1598  int64_t start,
1599  fc::time_point_sec stop,
1600  unsigned limit )const
1601 {
1602  return my->get_trade_history_by_sequence( base, quote, start, stop, limit );
1603 }
1604 
1606  const string& base,
1607  const string& quote,
1608  int64_t start,
1609  fc::time_point_sec stop,
1610  unsigned limit )const
1611 {
1612  FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." );
1613 
1614  const auto configured_limit = _app_options->api_limit_get_trade_history_by_sequence;
1615  FC_ASSERT( limit <= configured_limit,
1616  "limit can not be greater than ${configured_limit}",
1617  ("configured_limit", configured_limit) );
1618 
1619  FC_ASSERT( start >= 0 );
1620  int64_t start_seq = -start;
1621 
1622  auto assets = lookup_asset_symbols( {base, quote} );
1623  FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
1624  FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
1625 
1626  auto base_id = assets[0]->id;
1627  auto quote_id = assets[1]->id;
1628 
1629  if( base_id > quote_id ) std::swap( base_id, quote_id );
1630  const auto& history_idx = _db.get_index_type<graphene::market_history::history_index>().indices().get<by_key>();
1631  history_key hkey;
1632  hkey.base = base_id;
1633  hkey.quote = quote_id;
1634  hkey.sequence = start_seq;
1635 
1636  uint32_t count = 0;
1637  auto itr = history_idx.lower_bound( hkey );
1638  vector<market_trade> result;
1639 
1640  while( itr != history_idx.end() && count < limit
1641  && !( itr->key.base != base_id || itr->key.quote != quote_id || itr->time < stop ) )
1642  {
1643  if( itr->key.sequence == start_seq ) // found the key, should skip this and the other direction if found
1644  {
1645  auto next_itr = std::next(itr);
1646  if( next_itr != history_idx.end() && next_itr->key.base == base_id && next_itr->key.quote == quote_id
1647  && next_itr->time == itr->time && next_itr->op.is_maker != itr->op.is_maker )
1648  { // next_itr now could be the other direction // FIXME not 100% sure
1649  // skip the other direction
1650  itr = next_itr;
1651  }
1652  }
1653  else
1654  {
1655  market_trade trade;
1656 
1657  if( assets[0]->id == itr->op.receives.asset_id )
1658  {
1659  trade.amount = assets[1]->amount_to_string( itr->op.pays );
1660  trade.value = assets[0]->amount_to_string( itr->op.receives );
1661  }
1662  else
1663  {
1664  trade.amount = assets[1]->amount_to_string( itr->op.receives );
1665  trade.value = assets[0]->amount_to_string( itr->op.pays );
1666  }
1667 
1668  trade.date = itr->time;
1669  trade.price = price_to_string( itr->op.fill_price, *assets[0], *assets[1] );
1670 
1671  if( itr->op.is_maker )
1672  {
1673  trade.sequence = -itr->key.sequence;
1674  trade.side1_account_id = itr->op.account_id;
1675  if(itr->op.receives.asset_id == assets[0]->id)
1676  trade.type = "sell";
1677  else
1678  trade.type = "buy";
1679  }
1680  else
1681  trade.side2_account_id = itr->op.account_id;
1682 
1683  auto next_itr = std::next(itr);
1684  // Trades are usually tracked in each direction, exception: for global settlement only one side is recorded
1685  if( next_itr != history_idx.end() && next_itr->key.base == base_id && next_itr->key.quote == quote_id
1686  && next_itr->time == itr->time && next_itr->op.is_maker != itr->op.is_maker )
1687  { // next_itr now could be the other direction // FIXME not 100% sure
1688  if( next_itr->op.is_maker )
1689  {
1690  trade.sequence = -next_itr->key.sequence;
1691  trade.side1_account_id = next_itr->op.account_id;
1692  if(next_itr->op.receives.asset_id == assets[0]->id)
1693  trade.type = "sell";
1694  else
1695  trade.type = "buy";
1696  }
1697  else
1698  trade.side2_account_id = next_itr->op.account_id;
1699  // skip the other direction
1700  itr = next_itr;
1701  }
1702 
1703  result.push_back( trade );
1704  ++count;
1705  }
1706 
1707  ++itr;
1708  }
1709 
1710  return result;
1711 }
1712 
1714 // //
1715 // Witnesses //
1716 // //
1718 
1719 vector<optional<witness_object>> database_api::get_witnesses(const vector<witness_id_type>& witness_ids)const
1720 {
1721  return my->get_witnesses( witness_ids );
1722 }
1723 
1724 vector<optional<witness_object>> database_api_impl::get_witnesses(const vector<witness_id_type>& witness_ids)const
1725 {
1726  vector<optional<witness_object>> result; result.reserve(witness_ids.size());
1727  std::transform(witness_ids.begin(), witness_ids.end(), std::back_inserter(result),
1728  [this](witness_id_type id) -> optional<witness_object> {
1729  if(auto o = _db.find(id))
1730  return *o;
1731  return {};
1732  });
1733  return result;
1734 }
1735 
1736 fc::optional<witness_object> database_api::get_witness_by_account(const std::string account_id_or_name)const
1737 {
1738  return my->get_witness_by_account( account_id_or_name );
1739 }
1740 
1742 {
1743  const auto& idx = _db.get_index_type<witness_index>().indices().get<by_account>();
1744  const account_id_type account = get_account_from_string(account_id_or_name)->id;
1745  auto itr = idx.find(account);
1746  if( itr != idx.end() )
1747  return *itr;
1748  return {};
1749 }
1750 
1751 map<string, witness_id_type> database_api::lookup_witness_accounts( const string& lower_bound_name,
1752  uint32_t limit )const
1753 {
1754  return my->lookup_witness_accounts( lower_bound_name, limit );
1755 }
1756 
1757 map<string, witness_id_type> database_api_impl::lookup_witness_accounts( const string& lower_bound_name,
1758  uint32_t limit )const
1759 {
1760  FC_ASSERT( _app_options, "Internal error" );
1761  const auto configured_limit = _app_options->api_limit_lookup_witness_accounts;
1762  FC_ASSERT( limit <= configured_limit,
1763  "limit can not be greater than ${configured_limit}",
1764  ("configured_limit", configured_limit) );
1765 
1766  const auto& witnesses_by_id = _db.get_index_type<witness_index>().indices().get<by_id>();
1767 
1768  // we want to order witnesses by account name, but that name is in the account object
1769  // so the witness_index doesn't have a quick way to access it.
1770  // get all the names and look them all up, sort them, then figure out what
1771  // records to return. This could be optimized, but we expect the
1772  // number of witnesses to be few and the frequency of calls to be rare
1773  std::map<std::string, witness_id_type> witnesses_by_account_name;
1774  for (const witness_object& witness : witnesses_by_id)
1775  if (auto account_iter = _db.find(witness.witness_account))
1776  if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name
1777  witnesses_by_account_name.insert(std::make_pair(account_iter->name, witness.id));
1778 
1779  auto end_iter = witnesses_by_account_name.begin();
1780  while (end_iter != witnesses_by_account_name.end() && limit--)
1781  ++end_iter;
1782  witnesses_by_account_name.erase(end_iter, witnesses_by_account_name.end());
1783  return witnesses_by_account_name;
1784 }
1785 
1787 {
1788  return my->get_witness_count();
1789 }
1790 
1792 {
1793  return _db.get_index_type<witness_index>().indices().size();
1794 }
1795 
1797 // //
1798 // Committee members //
1799 // //
1801 
1802 vector<optional<committee_member_object>> database_api::get_committee_members(
1803  const vector<committee_member_id_type>& committee_member_ids )const
1804 {
1805  return my->get_committee_members( committee_member_ids );
1806 }
1807 
1808 vector<optional<committee_member_object>> database_api_impl::get_committee_members(
1809  const vector<committee_member_id_type>& committee_member_ids )const
1810 {
1811  vector<optional<committee_member_object>> result; result.reserve(committee_member_ids.size());
1812  std::transform(committee_member_ids.begin(), committee_member_ids.end(), std::back_inserter(result),
1813  [this](committee_member_id_type id) -> optional<committee_member_object> {
1814  if(auto o = _db.find(id))
1815  return *o;
1816  return {};
1817  });
1818  return result;
1819 }
1820 
1822  const std::string account_id_or_name )const
1823 {
1824  return my->get_committee_member_by_account( account_id_or_name );
1825 }
1826 
1828  const std::string account_id_or_name )const
1829 {
1830  const auto& idx = _db.get_index_type<committee_member_index>().indices().get<by_account>();
1831  const account_id_type account = get_account_from_string(account_id_or_name)->id;
1832  auto itr = idx.find(account);
1833  if( itr != idx.end() )
1834  return *itr;
1835  return {};
1836 }
1837 
1838 map<string, committee_member_id_type> database_api::lookup_committee_member_accounts(
1839  const string& lower_bound_name, uint32_t limit )const
1840 {
1841  return my->lookup_committee_member_accounts( lower_bound_name, limit );
1842 }
1843 
1844 map<string, committee_member_id_type> database_api_impl::lookup_committee_member_accounts(
1845  const string& lower_bound_name, uint32_t limit )const
1846 {
1847  FC_ASSERT( _app_options, "Internal error" );
1848  const auto configured_limit = _app_options->api_limit_lookup_committee_member_accounts;
1849  FC_ASSERT( limit <= configured_limit,
1850  "limit can not be greater than ${configured_limit}",
1851  ("configured_limit", configured_limit) );
1852 
1853  const auto& committee_members_by_id = _db.get_index_type<committee_member_index>().indices().get<by_id>();
1854 
1855  // we want to order committee_members by account name, but that name is in the account object
1856  // so the committee_member_index doesn't have a quick way to access it.
1857  // get all the names and look them all up, sort them, then figure out what
1858  // records to return. This could be optimized, but we expect the
1859  // number of committee_members to be few and the frequency of calls to be rare
1860  std::map<std::string, committee_member_id_type> committee_members_by_account_name;
1861  for (const committee_member_object& committee_member : committee_members_by_id)
1862  if (auto account_iter = _db.find(committee_member.committee_member_account))
1863  if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name
1864  committee_members_by_account_name.insert(std::make_pair(account_iter->name, committee_member.id));
1865 
1866  auto end_iter = committee_members_by_account_name.begin();
1867  while (end_iter != committee_members_by_account_name.end() && limit--)
1868  ++end_iter;
1869  committee_members_by_account_name.erase(end_iter, committee_members_by_account_name.end());
1870  return committee_members_by_account_name;
1871 }
1872 
1874 {
1875  return my->get_committee_count();
1876 }
1877 
1879 {
1880  return _db.get_index_type<committee_member_index>().indices().size();
1881 }
1882 
1883 
1885 // //
1886 // Workers //
1887 // //
1889 
1890 vector<worker_object> database_api::get_all_workers( const optional<bool> is_expired )const
1891 {
1892  return my->get_all_workers( is_expired );
1893 }
1894 
1895 vector<worker_object> database_api_impl::get_all_workers( const optional<bool> is_expired )const
1896 {
1897  vector<worker_object> result;
1898 
1899  if( !is_expired.valid() ) // query for all workers
1900  {
1901  const auto& workers_idx = _db.get_index_type<worker_index>().indices().get<by_id>();
1902  result.reserve( workers_idx.size() );
1903  for( const auto& w : workers_idx )
1904  {
1905  result.push_back( w );
1906  }
1907  }
1908  else // query for workers that are expired only or not expired only
1909  {
1910  const time_point_sec now = _db.head_block_time();
1911  const auto& workers_idx = _db.get_index_type<worker_index>().indices().get<by_end_date>();
1912  auto itr = *is_expired ? workers_idx.begin() : workers_idx.lower_bound( now );
1913  auto end = *is_expired ? workers_idx.upper_bound( now ) : workers_idx.end();
1914  for( ; itr != end; ++itr )
1915  {
1916  result.push_back( *itr );
1917  }
1918  }
1919 
1920  return result;
1921 }
1922 
1923 vector<worker_object> database_api::get_workers_by_account(const std::string account_id_or_name)const
1924 {
1925  return my->get_workers_by_account( account_id_or_name );
1926 }
1927 
1928 vector<worker_object> database_api_impl::get_workers_by_account(const std::string account_id_or_name)const
1929 {
1930  vector<worker_object> result;
1931  const auto& workers_idx = _db.get_index_type<worker_index>().indices().get<by_account>();
1932 
1933  const account_id_type account = get_account_from_string(account_id_or_name)->id;
1934  auto range = workers_idx.equal_range(account);
1935  for(auto itr = range.first; itr != range.second; ++itr)
1936  {
1937  result.push_back( *itr );
1938  }
1939  return result;
1940 }
1941 
1943 {
1944  return my->get_worker_count();
1945 }
1946 
1948 {
1949  return _db.get_index_type<worker_index>().indices().size();
1950 }
1951 
1952 
1953 
1955 // //
1956 // Votes //
1957 // //
1959 
1960 vector<variant> database_api::lookup_vote_ids( const vector<vote_id_type>& votes )const
1961 {
1962  return my->lookup_vote_ids( votes );
1963 }
1964 
1965 vector<variant> database_api_impl::lookup_vote_ids( const vector<vote_id_type>& votes )const
1966 {
1967  FC_ASSERT( _app_options, "Internal error" );
1968  const auto configured_limit = _app_options->api_limit_lookup_vote_ids;
1969  FC_ASSERT( votes.size() <= configured_limit,
1970  "Number of querying votes can not be greater than ${configured_limit}",
1971  ("configured_limit", configured_limit) );
1972 
1973  const auto& witness_idx = _db.get_index_type<witness_index>().indices().get<by_vote_id>();
1974  const auto& committee_idx = _db.get_index_type<committee_member_index>().indices().get<by_vote_id>();
1975  const auto& for_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_for>();
1976  const auto& against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>();
1977 
1978  vector<variant> result;
1979  result.reserve( votes.size() );
1980  for( auto id : votes )
1981  {
1982  switch( id.type() )
1983  {
1985  {
1986  auto itr = committee_idx.find( id );
1987  if( itr != committee_idx.end() )
1988  result.emplace_back( variant( *itr, 2 ) ); // Depth of committee_member_object is 1, add 1 to be safe
1989  else
1990  result.emplace_back( variant() );
1991  break;
1992  }
1993  case vote_id_type::witness:
1994  {
1995  auto itr = witness_idx.find( id );
1996  if( itr != witness_idx.end() )
1997  result.emplace_back( variant( *itr, 2 ) ); // Depth of witness_object is 1, add 1 here to be safe
1998  else
1999  result.emplace_back( variant() );
2000  break;
2001  }
2002  case vote_id_type::worker:
2003  {
2004  auto itr = for_worker_idx.find( id );
2005  if( itr != for_worker_idx.end() ) {
2006  result.emplace_back( variant( *itr, 4 ) ); // Depth of worker_object is 3, add 1 here to be safe.
2007  // If we want to extract the balance object inside,
2008  // need to increase this value
2009  }
2010  else {
2011  auto itr = against_worker_idx.find( id );
2012  if( itr != against_worker_idx.end() ) {
2013  result.emplace_back( variant( *itr, 4 ) ); // Depth of worker_object is 3, add 1 here to be safe.
2014  // If we want to extract the balance object inside,
2015  // need to increase this value
2016  }
2017  else {
2018  result.emplace_back( variant() );
2019  }
2020  }
2021  break;
2022  }
2023  case vote_id_type::VOTE_TYPE_COUNT: break; // supress unused enum value warnings
2024  default:
2025  FC_CAPTURE_AND_THROW( fc::out_of_range_exception, (id) );
2026  }
2027  }
2028  return result;
2029 }
2030 
2032 // //
2033 // Authority / validation //
2034 // //
2036 
2037 std::string database_api::get_transaction_hex(const signed_transaction& trx)const
2038 {
2039  return my->get_transaction_hex( trx );
2040 }
2041 
2042 std::string database_api_impl::get_transaction_hex(const signed_transaction& trx)const
2043 {
2044  return fc::to_hex(fc::raw::pack(trx));
2045 }
2046 
2048  const signed_transaction &trx) const
2049 {
2050  return my->get_transaction_hex_without_sig(trx);
2051 }
2052 
2054  const signed_transaction &trx) const
2055 {
2056  return fc::to_hex(fc::raw::pack(static_cast<transaction>(trx)));
2057 }
2058 
2059 set<public_key_type> database_api::get_required_signatures( const signed_transaction& trx,
2060  const flat_set<public_key_type>& available_keys )const
2061 {
2062  return my->get_required_signatures( trx, available_keys );
2063 }
2064 
2065 set<public_key_type> database_api_impl::get_required_signatures( const signed_transaction& trx,
2066  const flat_set<public_key_type>& available_keys )const
2067 {
2068  auto chain_time = _db.head_block_time();
2069  bool allow_non_immediate_owner = ( chain_time >= HARDFORK_CORE_584_TIME );
2070  bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( chain_time );
2071  auto result = trx.get_required_signatures( _db.get_chain_id(),
2072  available_keys,
2073  [&]( account_id_type id ){ return &id(_db).active; },
2074  [&]( account_id_type id ){ return &id(_db).owner; },
2075  allow_non_immediate_owner,
2076  ignore_custom_op_reqd_auths,
2078  return result;
2079 }
2080 
2081 set<public_key_type> database_api::get_potential_signatures( const signed_transaction& trx )const
2082 {
2083  return my->get_potential_signatures( trx );
2084 }
2085 set<address> database_api::get_potential_address_signatures( const signed_transaction& trx )const
2086 {
2087  return my->get_potential_address_signatures( trx );
2088 }
2089 
2090 set<public_key_type> database_api_impl::get_potential_signatures( const signed_transaction& trx )const
2091 {
2092  auto chain_time = _db.head_block_time();
2093  bool allow_non_immediate_owner = ( chain_time >= HARDFORK_CORE_584_TIME );
2094  bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( chain_time );
2095 
2096  set<public_key_type> result;
2097  auto get_active = [this, &result]( account_id_type id ){
2098  const auto& auth = id( _db ).active;
2099  for( const auto& k : auth.get_keys() )
2100  result.insert( k );
2101  return &auth;
2102  };
2103  auto get_owner = [this, &result]( account_id_type id ){
2104  const auto& auth = id( _db ).owner;
2105  for( const auto& k : auth.get_keys() )
2106  result.insert( k );
2107  return &auth;
2108  };
2109 
2110  trx.get_required_signatures( _db.get_chain_id(),
2111  flat_set<public_key_type>(),
2112  get_active, get_owner,
2113  allow_non_immediate_owner,
2114  ignore_custom_op_reqd_auths,
2116 
2117  // Insert keys in required "other" authories
2118  flat_set<account_id_type> required_active;
2119  flat_set<account_id_type> required_owner;
2120  vector<authority> other;
2121  trx.get_required_authorities( required_active, required_owner, other, ignore_custom_op_reqd_auths );
2122  for( const auto& auth : other )
2123  for( const auto& key : auth.get_keys() )
2124  result.insert( key );
2125 
2126  return result;
2127 }
2128 
2129 set<address> database_api_impl::get_potential_address_signatures( const signed_transaction& trx )const
2130 {
2131  auto chain_time = _db.head_block_time();
2132  bool allow_non_immediate_owner = ( chain_time >= HARDFORK_CORE_584_TIME );
2133  bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( chain_time );
2134 
2135  set<address> result;
2136  auto get_active = [this, &result]( account_id_type id ){
2137  const auto& auth = id( _db ).active;
2138  for( const auto& k : auth.get_addresses() )
2139  result.insert( k );
2140  return &auth;
2141  };
2142  auto get_owner = [this, &result]( account_id_type id ) {
2143  const auto& auth = id( _db ).owner;
2144  for (const auto& k : auth.get_addresses())
2145  result.insert( k );
2146  return &auth;
2147  };
2148 
2149  trx.get_required_signatures( _db.get_chain_id(),
2150  flat_set<public_key_type>(),
2151  get_active, get_owner,
2152  allow_non_immediate_owner,
2153  ignore_custom_op_reqd_auths,
2155  return result;
2156 }
2157 
2158 bool database_api::verify_authority( const signed_transaction& trx )const
2159 {
2160  return my->verify_authority( trx );
2161 }
2162 
2163 bool database_api_impl::verify_authority( const signed_transaction& trx )const
2164 {
2165  bool allow_non_immediate_owner = ( _db.head_block_time() >= HARDFORK_CORE_584_TIME );
2166  trx.verify_authority( _db.get_chain_id(),
2167  [this]( account_id_type id ){ return &id(_db).active; },
2168  [this]( account_id_type id ){ return &id(_db).owner; },
2169  [this]( account_id_type id, const operation& op, rejected_predicate_map* rejects ) {
2170  return _db.get_viable_custom_authorities(id, op, rejects); },
2171  allow_non_immediate_owner,
2173  return true;
2174 }
2175 
2176 bool database_api::verify_account_authority( const string& account_name_or_id,
2177  const flat_set<public_key_type>& signers )const
2178 {
2179  return my->verify_account_authority( account_name_or_id, signers );
2180 }
2181 
2182 bool database_api_impl::verify_account_authority( const string& account_name_or_id,
2183  const flat_set<public_key_type>& keys )const
2184 {
2185  // create a dummy transfer
2186  transfer_operation op;
2187  op.from = get_account_from_string(account_name_or_id)->id;
2188  std::vector<operation> ops;
2189  ops.emplace_back(op);
2190 
2191  try
2192  {
2194  [this]( account_id_type id ){ return &id(_db).active; },
2195  [this]( account_id_type id ){ return &id(_db).owner; },
2196  // Use a no-op lookup for custom authorities; we don't want it even if one does apply for our dummy op
2197  [](auto, auto, auto*) { return vector<authority>(); },
2198  true, MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(_db.head_block_time()) );
2199  }
2200  catch (fc::exception& ex)
2201  {
2202  return false;
2203  }
2204 
2205  return true;
2206 }
2207 
2208 processed_transaction database_api::validate_transaction( const signed_transaction& trx )const
2209 {
2210  return my->validate_transaction( trx );
2211 }
2212 
2214 {
2215  return _db.validate_transaction(trx);
2216 }
2217 
2218 vector< fc::variant > database_api::get_required_fees( const vector<operation>& ops,
2219  const std::string& asset_id_or_symbol )const
2220 {
2221  return my->get_required_fees( ops, asset_id_or_symbol );
2222 }
2223 
2229 {
2231  const fee_schedule& _current_fee_schedule,
2232  const price& _core_exchange_rate,
2233  uint32_t _max_recursion
2234  )
2235  : current_fee_schedule(_current_fee_schedule),
2236  core_exchange_rate(_core_exchange_rate),
2237  max_recursion(_max_recursion)
2238  {}
2239 
2241  {
2243  {
2244  return set_proposal_create_op_fees( op );
2245  }
2246  else
2247  {
2248  asset fee = current_fee_schedule.set_fee( op, core_exchange_rate );
2249  fc::variant result;
2251  return result;
2252  }
2253  }
2254 
2256  {
2257  proposal_create_operation& op = proposal_create_op.get<proposal_create_operation>();
2258  std::pair< asset, fc::variants > result;
2259  for( op_wrapper& prop_op : op.proposed_ops )
2260  {
2261  FC_ASSERT( current_recursion < max_recursion );
2262  ++current_recursion;
2263  result.second.push_back( set_op_fees( prop_op.op ) );
2264  --current_recursion;
2265  }
2266  // we need to do this on the boxed version, which is why we use
2267  // two mutually recursive functions instead of a visitor
2268  result.first = current_fee_schedule.set_fee( proposal_create_op, core_exchange_rate );
2269  fc::variant vresult;
2270  fc::to_variant( result, vresult, GRAPHENE_NET_MAX_NESTED_OBJECTS );
2271  return vresult;
2272  }
2273 
2274  const fee_schedule& current_fee_schedule;
2276  uint32_t max_recursion;
2277  uint32_t current_recursion = 0;
2278 };
2279 
2280 vector< fc::variant > database_api_impl::get_required_fees( const vector<operation>& ops,
2281  const std::string& asset_id_or_symbol )const
2282 {
2283  vector< operation > _ops = ops;
2284  //
2285  // we copy the ops because we need to mutate an operation to reliably
2286  // determine its fee, see #435
2287  //
2288 
2289  vector< fc::variant > result;
2290  result.reserve(ops.size());
2291  const asset_object& a = *get_asset_from_string(asset_id_or_symbol);
2292  get_required_fees_helper helper(
2296  for( operation& op : _ops )
2297  {
2298  result.push_back( helper.set_op_fees( op ) );
2299  }
2300  return result;
2301 }
2302 
2304 // //
2305 // Proposed transactions //
2306 // //
2308 
2309 vector<proposal_object> database_api::get_proposed_transactions( const std::string account_id_or_name )const
2310 {
2311  return my->get_proposed_transactions( account_id_or_name );
2312 }
2313 
2314 vector<proposal_object> database_api_impl::get_proposed_transactions( const std::string account_id_or_name )const
2315 {
2316  // api_helper_indexes plugin is required for accessing the secondary index
2318  "api_helper_indexes plugin is not enabled on this server." );
2319 
2320  const auto& proposal_idx = _db.get_index_type< primary_index< proposal_index > >();
2321  const auto& proposals_by_account = proposal_idx.get_secondary_index<graphene::chain::required_approval_index>();
2322 
2323  vector<proposal_object> result;
2324  const account_id_type id = get_account_from_string(account_id_or_name)->id;
2325 
2326  auto required_approvals_itr = proposals_by_account._account_to_proposals.find( id );
2327  if( required_approvals_itr != proposals_by_account._account_to_proposals.end() )
2328  {
2329  result.reserve( required_approvals_itr->second.size() );
2330  for( auto proposal_id : required_approvals_itr->second )
2331  {
2332  result.push_back( proposal_id(_db) );
2333  }
2334  }
2335  return result;
2336 }
2337 
2339 // //
2340 // Blinded balances //
2341 // //
2343 
2344 vector<blinded_balance_object> database_api::get_blinded_balances(
2345  const flat_set<commitment_type>& commitments )const
2346 {
2347  return my->get_blinded_balances( commitments );
2348 }
2349 
2350 vector<blinded_balance_object> database_api_impl::get_blinded_balances(
2351  const flat_set<commitment_type>& commitments )const
2352 {
2353  vector<blinded_balance_object> result; result.reserve(commitments.size());
2354  const auto& bal_idx = _db.get_index_type<blinded_balance_index>();
2355  const auto& by_commitment_idx = bal_idx.indices().get<by_commitment>();
2356  for( const auto& c : commitments )
2357  {
2358  auto itr = by_commitment_idx.find( c );
2359  if( itr != by_commitment_idx.end() )
2360  result.push_back( *itr );
2361  }
2362  return result;
2363 }
2364 
2366 // //
2367 // Withdrawals //
2368 // //
2370 
2371 vector<withdraw_permission_object> database_api::get_withdraw_permissions_by_giver(
2372  const std::string account_id_or_name,
2373  withdraw_permission_id_type start,
2374  uint32_t limit)const
2375 {
2376  return my->get_withdraw_permissions_by_giver( account_id_or_name, start, limit );
2377 }
2378 
2379 vector<withdraw_permission_object> database_api_impl::get_withdraw_permissions_by_giver(
2380  const std::string account_id_or_name,
2381  withdraw_permission_id_type start,
2382  uint32_t limit)const
2383 {
2384  FC_ASSERT( _app_options, "Internal error" );
2385  const auto configured_limit = _app_options->api_limit_get_withdraw_permissions_by_giver;
2386  FC_ASSERT( limit <= configured_limit,
2387  "limit can not be greater than ${configured_limit}",
2388  ("configured_limit", configured_limit) );
2389 
2390  vector<withdraw_permission_object> result;
2391 
2392  const auto& withdraw_idx = _db.get_index_type<withdraw_permission_index>().indices().get<by_from>();
2393  auto withdraw_index_end = withdraw_idx.end();
2394  const account_id_type account = get_account_from_string(account_id_or_name)->id;
2395  auto withdraw_itr = withdraw_idx.lower_bound(boost::make_tuple(account, start));
2396  while( withdraw_itr != withdraw_index_end && withdraw_itr->withdraw_from_account == account
2397  && result.size() < limit )
2398  {
2399  result.push_back(*withdraw_itr);
2400  ++withdraw_itr;
2401  }
2402  return result;
2403 }
2404 
2405 vector<withdraw_permission_object> database_api::get_withdraw_permissions_by_recipient(
2406  const std::string account_id_or_name,
2407  withdraw_permission_id_type start,
2408  uint32_t limit)const
2409 {
2410  return my->get_withdraw_permissions_by_recipient( account_id_or_name, start, limit );
2411 }
2412 
2414  const std::string account_id_or_name,
2415  withdraw_permission_id_type start,
2416  uint32_t limit)const
2417 {
2418  FC_ASSERT( _app_options, "Internal error" );
2419  const auto configured_limit = _app_options->api_limit_get_withdraw_permissions_by_recipient;
2420  FC_ASSERT( limit <= configured_limit,
2421  "limit can not be greater than ${configured_limit}",
2422  ("configured_limit", configured_limit) );
2423 
2424  vector<withdraw_permission_object> result;
2425 
2426  const auto& withdraw_idx = _db.get_index_type<withdraw_permission_index>().indices().get<by_authorized>();
2427  auto withdraw_index_end = withdraw_idx.end();
2428  const account_id_type account = get_account_from_string(account_id_or_name)->id;
2429  auto withdraw_itr = withdraw_idx.lower_bound(boost::make_tuple(account, start));
2430  while(withdraw_itr != withdraw_index_end && withdraw_itr->authorized_account == account && result.size() < limit)
2431  {
2432  result.push_back(*withdraw_itr);
2433  ++withdraw_itr;
2434  }
2435  return result;
2436 }
2437 
2439 // //
2440 // HTLC //
2441 // //
2443 
2444 optional<htlc_object> database_api::get_htlc( htlc_id_type id, optional<bool> subscribe )const
2445 {
2446  return my->get_htlc( id, subscribe );
2447 }
2448 
2449 fc::optional<htlc_object> database_api_impl::get_htlc( htlc_id_type id, optional<bool> subscribe )const
2450 {
2451  auto obj = get_objects( { id }, subscribe ).front();
2452  if ( !obj.is_null() )
2453  {
2454  return fc::optional<htlc_object>(obj.template as<htlc_object>(GRAPHENE_MAX_NESTED_OBJECTS));
2455  }
2456  return fc::optional<htlc_object>();
2457 }
2458 
2459 vector<htlc_object> database_api::get_htlc_by_from( const std::string account_id_or_name,
2460  htlc_id_type start, uint32_t limit )const
2461 {
2462  return my->get_htlc_by_from(account_id_or_name, start, limit);
2463 }
2464 
2465 vector<htlc_object> database_api_impl::get_htlc_by_from( const std::string account_id_or_name,
2466  htlc_id_type start, uint32_t limit ) const
2467 {
2468  FC_ASSERT( _app_options, "Internal error" );
2469  const auto configured_limit = _app_options->api_limit_get_htlc_by;
2470  FC_ASSERT( limit <= configured_limit,
2471  "limit can not be greater than ${configured_limit}",
2472  ("configured_limit", configured_limit) );
2473 
2474  vector<htlc_object> result;
2475 
2476  const auto& htlc_idx = _db.get_index_type< htlc_index >().indices().get< by_from_id >();
2477  auto htlc_index_end = htlc_idx.end();
2478  const account_id_type account = get_account_from_string(account_id_or_name)->id;
2479  auto htlc_itr = htlc_idx.lower_bound(boost::make_tuple(account, start));
2480 
2481  while(htlc_itr != htlc_index_end && htlc_itr->transfer.from == account && result.size() < limit)
2482  {
2483  result.push_back(*htlc_itr);
2484  ++htlc_itr;
2485  }
2486  return result;
2487 }
2488 
2489 vector<htlc_object> database_api::get_htlc_by_to( const std::string account_id_or_name,
2490  htlc_id_type start, uint32_t limit )const
2491 {
2492  return my->get_htlc_by_to(account_id_or_name, start, limit);
2493 }
2494 
2495 vector<htlc_object> database_api_impl::get_htlc_by_to( const std::string account_id_or_name,
2496  htlc_id_type start, uint32_t limit ) const
2497 {
2498  FC_ASSERT( _app_options, "Internal error" );
2499  const auto configured_limit = _app_options->api_limit_get_htlc_by;
2500  FC_ASSERT( limit <= configured_limit,
2501  "limit can not be greater than ${configured_limit}",
2502  ("configured_limit", configured_limit) );
2503 
2504  vector<htlc_object> result;
2505 
2506  const auto& htlc_idx = _db.get_index_type< htlc_index >().indices().get< by_to_id >();
2507  auto htlc_index_end = htlc_idx.end();
2508  const account_id_type account = get_account_from_string(account_id_or_name)->id;
2509  auto htlc_itr = htlc_idx.lower_bound(boost::make_tuple(account, start));
2510 
2511  while(htlc_itr != htlc_index_end && htlc_itr->transfer.to == account && result.size() < limit)
2512  {
2513  result.push_back(*htlc_itr);
2514  ++htlc_itr;
2515  }
2516  return result;
2517 }
2518 
2519 vector<htlc_object> database_api::list_htlcs(const htlc_id_type start, uint32_t limit)const
2520 {
2521  return my->list_htlcs(start, limit);
2522 }
2523 
2524 vector<htlc_object> database_api_impl::list_htlcs(const htlc_id_type start, uint32_t limit) const
2525 {
2526  FC_ASSERT( _app_options, "Internal error" );
2527  const auto configured_limit = _app_options->api_limit_list_htlcs;
2528  FC_ASSERT( limit <= configured_limit,
2529  "limit can not be greater than ${configured_limit}",
2530  ("configured_limit", configured_limit) );
2531 
2532  vector<htlc_object> result;
2533  const auto& htlc_idx = _db.get_index_type<htlc_index>().indices().get<by_id>();
2534  auto itr = htlc_idx.lower_bound(start);
2535  while(itr != htlc_idx.end() && result.size() < limit)
2536  {
2537  result.push_back(*itr);
2538  ++itr;
2539  }
2540  return result;
2541 }
2542 
2544 // //
2545 // Private methods //
2546 // //
2548 
2549 const account_object* database_api_impl::get_account_from_string( const std::string& name_or_id,
2550  bool throw_if_not_found ) const
2551 {
2552  // TODO cache the result to avoid repeatly fetching from db
2553  FC_ASSERT( name_or_id.size() > 0);
2554  const account_object* account = nullptr;
2555  if (std::isdigit(name_or_id[0]))
2556  account = _db.find(fc::variant(name_or_id, 1).as<account_id_type>(1));
2557  else
2558  {
2559  const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
2560  auto itr = idx.find(name_or_id);
2561  if (itr != idx.end())
2562  account = &*itr;
2563  }
2564  if(throw_if_not_found)
2565  FC_ASSERT( account, "no such account" );
2566  return account;
2567 }
2568 
2569 const asset_object* database_api_impl::get_asset_from_string( const std::string& symbol_or_id,
2570  bool throw_if_not_found ) const
2571 {
2572  // TODO cache the result to avoid repeatly fetching from db
2573  FC_ASSERT( symbol_or_id.size() > 0);
2574  const asset_object* asset = nullptr;
2575  if (std::isdigit(symbol_or_id[0]))
2576  asset = _db.find(fc::variant(symbol_or_id, 1).as<asset_id_type>(1));
2577  else
2578  {
2579  const auto& idx = _db.get_index_type<asset_index>().indices().get<by_symbol>();
2580  auto itr = idx.find(symbol_or_id);
2581  if (itr != idx.end())
2582  asset = &*itr;
2583  }
2584  if(throw_if_not_found)
2585  FC_ASSERT( asset, "no such asset" );
2586  return asset;
2587 }
2588 
2589 // helper function
2590 vector<optional<extended_asset_object>> database_api_impl::get_assets( const vector<asset_id_type>& asset_ids,
2591  optional<bool> subscribe )const
2592 {
2593  bool to_subscribe = get_whether_to_subscribe( subscribe );
2594  vector<optional<extended_asset_object>> result; result.reserve(asset_ids.size());
2595  std::transform(asset_ids.begin(), asset_ids.end(), std::back_inserter(result),
2596  [this,to_subscribe](asset_id_type id) -> optional<extended_asset_object> {
2597  if(auto o = _db.find(id))
2598  {
2599  if( to_subscribe )
2600  subscribe_to_item( id );
2601  return extend_asset( *o );
2602  }
2603  return {};
2604  });
2605  return result;
2606 }
2607 
2608 // helper function
2609 vector<limit_order_object> database_api_impl::get_limit_orders( const asset_id_type a, const asset_id_type b,
2610  const uint32_t limit )const
2611 {
2612  FC_ASSERT( _app_options, "Internal error" );
2613  const auto configured_limit = _app_options->api_limit_get_limit_orders;
2614  FC_ASSERT( limit <= configured_limit,
2615  "limit can not be greater than ${configured_limit}",
2616  ("configured_limit", configured_limit) );
2617 
2618  const auto& limit_order_idx = _db.get_index_type<limit_order_index>();
2619  const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
2620 
2621  vector<limit_order_object> result;
2622  result.reserve(limit*2);
2623 
2624  uint32_t count = 0;
2625  auto limit_itr = limit_price_idx.lower_bound(price::max(a,b));
2626  auto limit_end = limit_price_idx.upper_bound(price::min(a,b));
2627  while(limit_itr != limit_end && count < limit)
2628  {
2629  result.push_back(*limit_itr);
2630  ++limit_itr;
2631  ++count;
2632  }
2633  count = 0;
2634  limit_itr = limit_price_idx.lower_bound(price::max(b,a));
2635  limit_end = limit_price_idx.upper_bound(price::min(b,a));
2636  while(limit_itr != limit_end && count < limit)
2637  {
2638  result.push_back(*limit_itr);
2639  ++limit_itr;
2640  ++count;
2641  }
2642 
2643  return result;
2644 }
2645 
2646 bool database_api_impl::is_impacted_account( const flat_set<account_id_type>& accounts)
2647 {
2648  if( !_subscribed_accounts.size() || !accounts.size() )
2649  return false;
2650 
2651  return std::any_of(accounts.begin(), accounts.end(), [this](const account_id_type& account) {
2652  return _subscribed_accounts.find(account) != _subscribed_accounts.end();
2653  });
2654 }
2655 
2656 void database_api_impl::broadcast_updates( const vector<variant>& updates )
2657 {
2658  if( updates.size() && _subscribe_callback ) {
2659  auto capture_this = shared_from_this();
2660  fc::async([capture_this,updates](){
2661  if(capture_this->_subscribe_callback)
2662  capture_this->_subscribe_callback( fc::variant(updates) );
2663  });
2664  }
2665 }
2666 
2668 {
2669  if( queue.size() )
2670  {
2671  auto capture_this = shared_from_this();
2672  fc::async([capture_this, this, queue](){
2673  for( const auto& item : queue )
2674  {
2675  auto sub = _market_subscriptions.find(item.first);
2676  if( sub != _market_subscriptions.end() )
2677  sub->second( fc::variant(item.second ) );
2678  }
2679  });
2680  }
2681 }
2682 
2683 void database_api_impl::on_objects_removed( const vector<object_id_type>& ids,
2684  const vector<const object*>& objs,
2685  const flat_set<account_id_type>& impacted_accounts )
2686 {
2687  handle_object_changed(_notify_remove_create, false, ids, impacted_accounts,
2688  [objs](object_id_type id) -> const object* {
2689  auto it = std::find_if(
2690  objs.begin(), objs.end(),
2691  [id](const object* o) {return o != nullptr && o->id == id;});
2692 
2693  if (it != objs.end())
2694  return *it;
2695 
2696  return nullptr;
2697  }
2698  );
2699 }
2700 
2701 void database_api_impl::on_objects_new( const vector<object_id_type>& ids,
2702  const flat_set<account_id_type>& impacted_accounts )
2703 {
2704  handle_object_changed(_notify_remove_create, true, ids, impacted_accounts,
2705  std::bind(&object_database::find_object, &_db, std::placeholders::_1)
2706  );
2707 }
2708 
2709 void database_api_impl::on_objects_changed( const vector<object_id_type>& ids,
2710  const flat_set<account_id_type>& impacted_accounts )
2711 {
2712  handle_object_changed(false, true, ids, impacted_accounts,
2713  std::bind(&object_database::find_object, &_db, std::placeholders::_1)
2714  );
2715 }
2716 
2718  bool full_object,
2719  const vector<object_id_type>& ids,
2720  const flat_set<account_id_type>& impacted_accounts,
2721  std::function<const object*(object_id_type id)> find_object )
2722 {
2723  if( _subscribe_callback )
2724  {
2725  vector<variant> updates;
2726 
2727  for(auto id : ids)
2728  {
2729  if( force_notify || is_subscribed_to_item(id) || is_impacted_account(impacted_accounts) )
2730  {
2731  if( full_object )
2732  {
2733  auto obj = find_object(id);
2734  if( obj )
2735  {
2736  updates.emplace_back( obj->to_variant() );
2737  }
2738  }
2739  else
2740  {
2741  updates.emplace_back( fc::variant( id, 1 ) );
2742  }
2743  }
2744  }
2745 
2746  if( updates.size() )
2747  broadcast_updates(updates);
2748  }
2749 
2750  if( _market_subscriptions.size() )
2751  {
2752  market_queue_type broadcast_queue;
2753 
2754  for(auto id : ids)
2755  {
2756  if( id.is<call_order_object>() )
2757  {
2758  enqueue_if_subscribed_to_market<call_order_object>( find_object(id), broadcast_queue, full_object );
2759  }
2760  else if( id.is<limit_order_object>() )
2761  {
2762  enqueue_if_subscribed_to_market<limit_order_object>( find_object(id), broadcast_queue, full_object );
2763  }
2764  else if( id.is<force_settlement_object>() )
2765  {
2766  enqueue_if_subscribed_to_market<force_settlement_object>( find_object(id), broadcast_queue,
2767  full_object );
2768  }
2769  }
2770 
2771  if( broadcast_queue.size() )
2772  broadcast_market_updates(broadcast_queue);
2773  }
2774 }
2775 
2780 {
2782  {
2783  auto capture_this = shared_from_this();
2784  block_id_type block_id = _db.head_block_id();
2785  fc::async([this,capture_this,block_id](){
2786  _block_applied_callback(fc::variant(block_id, 1));
2787  });
2788  }
2789 
2790  if(_market_subscriptions.size() == 0)
2791  return;
2792 
2793  const auto& ops = _db.get_applied_operations();
2794  map< std::pair<asset_id_type,asset_id_type>, vector<pair<operation, operation_result>> > subscribed_markets_ops;
2795  for(const optional< operation_history_object >& o_op : ops)
2796  {
2797  if( !o_op.valid() )
2798  continue;
2799  const operation_history_object& op = *o_op;
2800 
2801  optional< std::pair<asset_id_type,asset_id_type> > market;
2802  switch(op.op.which())
2803  {
2804  /* This is sent via the object_changed callback
2805  case operation::tag<limit_order_create_operation>::value:
2806  market = op.op.get<limit_order_create_operation>().get_market();
2807  break;
2808  */
2809  case operation::tag<fill_order_operation>::value:
2810  market = op.op.get<fill_order_operation>().get_market();
2811  break;
2812  /*
2813  case operation::tag<limit_order_cancel_operation>::value:
2814  */
2815  default: break;
2816  }
2817  if( market.valid() && _market_subscriptions.count(*market) )
2818  // FIXME this may cause fill_order_operation be pushed before order creation
2819  subscribed_markets_ops[*market].emplace_back(std::make_pair(op.op, op.result));
2820  }
2822  auto capture_this = shared_from_this();
2823  fc::async([this,capture_this,subscribed_markets_ops](){
2824  for(auto item : subscribed_markets_ops)
2825  {
2826  auto itr = _market_subscriptions.find(item.first);
2827  if(itr != _market_subscriptions.end())
2828  itr->second(fc::variant(item.second, GRAPHENE_NET_MAX_NESTED_OBJECTS));
2829  }
2830  });
2831 }
2832 
2833 } } // graphene::app
vector< force_settlement_object > get_settle_orders_by_account(const std::string &account_name_or_id, force_settlement_id_type start, uint32_t limit) const
Get forced settlement orders of a given account.
vector< balance_object > get_balance_objects(const vector< address > &addrs) const
Return all unclaimed balance objects for a list of addresses.
bool is_type() const
std::string price_to_string(const graphene::protocol::price &_price, const uint8_t base_precision, const uint8_t quote_precision)
Definition: util.cpp:68
vector< optional< extended_asset_object > > lookup_asset_symbols(const vector< string > &symbols_or_ids) const
Get a list of assets by symbol names or IDs.
vector< optional< account_object > > get_accounts(const vector< std::string > &account_names_or_ids, optional< bool > subscribe=optional< bool >()) const
Get a list of accounts by names or IDs.
tracks all of the proposal objects that requrie approval of an individual account.
std::string get_transaction_hex_without_sig(const signed_transaction &trx) const
#define FC_CAPTURE_AND_THROW(EXCEPTION_TYPE,...)
Definition: exception.hpp:357
vector< withdraw_permission_object > get_withdraw_permissions_by_giver(const std::string account_name_or_id, withdraw_permission_id_type start, uint32_t limit) const
Get non expired withdraw permission objects for a giver(ex:recurring customer)
set< address > get_potential_address_signatures(const signed_transaction &trx) const
vector< proposal_object > proposals
Definition: api_objects.hpp:72
map< pair< asset_id_type, asset_id_type >, std::function< void(const variant &)> > _market_subscriptions
auto async(Functor &&f, const char *desc FC_TASK_NAME_DEFAULT_ARG, priority prio=priority()) -> fc::future< decltype(f())>
Definition: thread.hpp:227
optional< signed_block > get_block(uint32_t block_num) const
void on_objects_changed(const vector< object_id_type > &ids, const flat_set< account_id_type > &impacted_accounts)
uint64_t api_limit_get_withdraw_permissions_by_recipient
Definition: application.hpp:73
void set_subscribe_callback(std::function< void(const variant &)> cb, bool notify_remove_create)
vector< optional< committee_member_object > > get_committee_members(const vector< committee_member_id_type > &committee_member_ids) const
map< string, account_id_type > lookup_accounts(const string &lower_bound_name, uint32_t limit, optional< bool > subscribe=optional< bool >()) const
Get names and IDs for registered accounts.
market_ticker get_ticker(const string &base, const string &quote, bool skip_order_book=false) const
processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const
vector< worker_object > get_workers_by_account(const std::string account_id_or_name) const
Wraps a derived index to intercept calls to create, modify, and remove so that callbacks may be fired...
Definition: index.hpp:309
fc::signal< void(const vector< object_id_type > &, const vector< const object * > &, const flat_set< account_id_type > &)> removed_objects
Definition: database.hpp:220
map< public_key_type, set< account_id_type >, pubkey_comparator > account_to_key_memberships
void set_block_applied_callback(std::function< void(const variant &block_id)> cb)
const T * find(object_id_type id) const
set< public_key_type > get_potential_signatures(const signed_transaction &trx) const
T as(uint32_t max_depth) const
Definition: variant.hpp:336
uint64_t get_asset_count() const
Get assets count.
set< public_key_type > get_potential_signatures(const signed_transaction &trx) const
vector< market_trade > get_trade_history_by_sequence(const string &base, const string &quote, int64_t start, fc::time_point_sec stop, unsigned limit=100) const
Returns trades for the market base:quote, ordered by time, most recent first. Note: Currently...
optional< block_header > get_block_header(uint32_t block_num) const
vector< vesting_balance_object > vesting_balances
Definition: api_objects.hpp:68
vector< call_order_object > call_orders
Definition: api_objects.hpp:70
const asset_object * get_asset_from_string(const std::string &symbol_or_id, bool throw_if_not_found=true) const
void pack(Stream &s, const flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:11
vector< withdraw_permission_object > withdraws_to
Definition: api_objects.hpp:75
void cancel_all_subscriptions()
Stop receiving any notifications.
bool verify_account_authority(const string &account_name_or_id, const flat_set< public_key_type > &signers) const
map< custom_authority_id_type, rejected_predicate > rejected_predicate_map
Definition: transaction.hpp:31
contains properties that only apply to bitassets (market issued assets)
necessary to support nested operations inside the proposal_create_operation
Definition: operations.hpp:133
vector< blinded_balance_object > get_blinded_balances(const flat_set< commitment_type > &commitments) const
return the set of blinded balance objects by commitment ID
std::function< void(const fc::variant &)> _pending_trx_callback
bool is_public_key_registered(string public_key) const
vector< optional< witness_object > > get_witnesses(const vector< witness_id_type > &witness_ids) const
Get a list of witnesses by ID.
boost::signals2::scoped_connection _change_connection
void set_auto_subscription(bool enable)
set< address > get_potential_address_signatures(const signed_transaction &trx) const
const object * find_object(object_id_type id) const
vector< account_balance_object > balances
Definition: api_objects.hpp:67
fc::signal< void(const signed_block &)> applied_block
Definition: database.hpp:197
#define GRAPHENE_MAX_NESTED_OBJECTS
Definition: config.hpp:31
void subscribe_to_market(std::function< void(const variant &)> callback, const std::string &a, const std::string &b)
uint32_t sec_since_epoch() const
Definition: time.hpp:90
dynamic_global_property_object get_dynamic_global_properties() const
tracks the history of all logical operations on blockchain stateAll operations and virtual operations...
vector< withdraw_permission_object > get_withdraw_permissions_by_giver(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit) const
void unsubscribe_from_market(const std::string &a, const std::string &b)
processed_transaction validate_transaction(const signed_transaction &trx) const
Validates a transaction against the current state without broadcasting it on the network.
This class represents an account on the object graphAccounts are the primary unit of authority on the...
bool is_impacted_account(const flat_set< account_id_type > &accounts)
vector< call_order_object > get_call_orders_by_account(const std::string &account_name_or_id, asset_id_type start, uint32_t limit) const
Get call orders (aka margin positions) of a given account.
Maintains global state information (committee_member list, current fees)This is an implementation det...
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
#define GRAPHENE_NET_MAX_NESTED_OBJECTS
Definition: config.hpp:110
vector< asset > get_vested_balances(const vector< balance_id_type > &objs) const
Calculate how much assets in the given balance objects are able to be claimed at current head block t...
vector< worker_object > get_workers_by_account(const std::string account_name_or_id) const
Get the workers owned by a given account.
An order-perserving dictionary of variant&#39;s.
void set_auto_subscription(bool enable)
Set auto-subscription behavior of follow-up API queries.
chain_id_type get_chain_id() const
Get the chain ID.
Definition: api.cpp:56
void on_objects_removed(const vector< object_id_type > &ids, const vector< const object * > &objs, const flat_set< account_id_type > &impacted_accounts)
vector< market_trade > get_trade_history(const string &base, const string &quote, fc::time_point_sec start, fc::time_point_sec stop, unsigned limit=100) const
Returns recent trades for the market base:quote, ordered by time, most recent first. Note: Currently, timezone offsets are not supported. The time must be UTC. The range is [stop, start). In case when there are more than 100 trades occurred in the same second, this API only returns the first 100 records, can use another API get_trade_history_by_sequence to query for the rest.
optional< block_header > get_block_header(uint32_t block_num) const
Retrieve a block header.
vector< balance_object > get_balance_objects(const vector< address > &addrs) const
fc::signal< void(const vector< object_id_type > &, const flat_set< account_id_type > &)> changed_objects
Definition: database.hpp:215
market_volume get_24_volume(const string &base, const string &quote) const
Returns the 24 hour volume for the market assetA:assetB.
vector< market_ticker > get_top_markets(uint32_t limit) const
Returns vector of tickers sorted by reverse base_volume Note: this API is experimental and subject to...
vector< htlc_object > htlcs_to
Definition: api_objects.hpp:77
asset get_balance(account_id_type owner, asset_id_type asset_id) const
Retrieve a particular account&#39;s balance in a given asset.
Definition: db_balance.cpp:35
void set_block_applied_callback(std::function< void(const variant &block_id)> cb)
Register a callback handle which will get notified when a block is pushed to database.
This secondary index will allow fast access to the balance objects that belonging to an account...
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
Definition: exception.hpp:56
database_api_impl(graphene::chain::database &db, const application_options *app_options)
map< uint32_t, optional< block_header > > get_block_header_batch(const vector< uint32_t > block_nums) const
Retrieve multiple block header by block numbers.
fc::time_point_sec date
fc::static_variant< transfer_operation, limit_order_create_operation, limit_order_cancel_operation, call_order_update_operation, fill_order_operation, account_create_operation, account_update_operation, account_whitelist_operation, account_upgrade_operation, account_transfer_operation, asset_create_operation, asset_update_operation, asset_update_bitasset_operation, asset_update_feed_producers_operation, asset_issue_operation, asset_reserve_operation, asset_fund_fee_pool_operation, asset_settle_operation, asset_global_settle_operation, asset_publish_feed_operation, witness_create_operation, witness_update_operation, proposal_create_operation, proposal_update_operation, proposal_delete_operation, withdraw_permission_create_operation, withdraw_permission_update_operation, withdraw_permission_claim_operation, withdraw_permission_delete_operation, committee_member_create_operation, committee_member_update_operation, committee_member_update_global_parameters_operation, vesting_balance_create_operation, vesting_balance_withdraw_operation, worker_create_operation, custom_operation, assert_operation, balance_claim_operation, override_transfer_operation, transfer_to_blind_operation, blind_transfer_operation, transfer_from_blind_operation, asset_settle_cancel_operation, asset_claim_fees_operation, fba_distribute_operation, bid_collateral_operation, execute_bid_operation, asset_claim_pool_operation, asset_update_issuer_operation, htlc_create_operation, htlc_redeem_operation, htlc_redeemed_operation, htlc_extend_operation, htlc_refund_operation, custom_authority_create_operation, custom_authority_update_operation, custom_authority_delete_operation, ticket_create_operation, ticket_update_operation >
std::vector< variant > variants
Definition: variant.hpp:170
void set_pending_transaction_callback(std::function< void(const variant &)> cb)
void broadcast_updates(const vector< variant > &updates)
std::function< void(const fc::variant &)> _block_applied_callback
vector< htlc_object > list_htlcs(const htlc_id_type lower_bound_id, uint32_t limit) const
account_id_type side2_account_id
asset_id_type get_asset_id_from_string(const std::string &symbol_or_id) const
Get asset ID from an asset symbol or ID.
#define FC_THROW(...)
Definition: exception.hpp:366
boost::signals2::scoped_connection _pending_trx_connection
vector< account_id_type > get_account_references(const std::string account_name_or_id) const
Get all accounts that refer to the specified account in their owner or active authorities.
optional< vesting_balance_object > cashback_balance
Definition: api_objects.hpp:66
bool get_whether_to_subscribe(optional< bool > subscribe) const
vector< extended_asset_object > get_assets_by_issuer(const std::string &issuer_name_or_id, asset_id_type start, uint32_t limit) const
vector< force_settlement_object > settle_orders
Definition: api_objects.hpp:71
#define GRAPHENE_DB_MAX_INSTANCE_ID
Definition: object_id.hpp:28
vector< limit_order_object > get_limit_orders(const std::string &a, const std::string &b, uint32_t limit) const
const vesting_balance_object & cashback_balance(const DB &db) const
bool verify_authority(const signed_transaction &trx) const
account_id_type side1_account_id
const global_property_object & get_global_properties() const
Definition: db_getter.cpp:44
vector< limit_order_object > get_account_limit_orders(const string &account_name_or_id, const string &base, const string &quote, uint32_t limit=101, optional< limit_order_id_type > ostart_id=optional< limit_order_id_type >(), optional< price > ostart_price=optional< price >())
Fetch all orders relevant to the specified account and specified market, result orders are sorted des...
market_volume get_24_volume(const string &base, const string &quote) const
tag_type which() const
const T & get(object_id_type id) const
price min() const
Definition: asset.hpp:131
optional< signed_block > fetch_block_by_number(uint32_t num) const
Definition: db_block.cpp:75
fc::optional< witness_object > get_witness_by_account(const std::string account_name_or_id) const
Get the witness owned by a given account.
std::string get_transaction_hex_without_sig(const signed_transaction &trx) const
Get a hexdump of the serialized binary form of a signatures-stripped transaction. ...
The proposal_create_operation creates a transaction proposal, for use in multi-sig scenariosCreates a...
Definition: proposal.hpp:70
vector< optional< witness_object > > get_witnesses(const vector< witness_id_type > &witness_ids) const
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
vector< extended_asset_object > get_assets_by_issuer(const std::string &issuer_name_or_id, asset_id_type start, uint32_t limit) const
Get assets issued (owned) by a given account.
vector< authority > get_viable_custom_authorities(account_id_type account, const operation &op, rejected_predicate_map *rejected_authorities=nullptr) const
Get a list of custom authorities which can validate the provided operation for the provided account...
Definition: db_getter.cpp:99
vector< call_order_object > get_call_orders(const std::string &a, uint32_t limit) const
fc::optional< committee_member_object > get_committee_member_by_account(const std::string account_id_or_name) const
vector< htlc_object > get_htlc_by_to(const std::string account_name_or_id, htlc_id_type start, uint32_t limit) const
Get non expired HTLC objects using the receiver account.
fc::signal< void(const signed_transaction &)> on_pending_transaction
Definition: database.hpp:203
vector< htlc_object > get_htlc_by_to(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const
std::set< account_id_type > _subscribed_accounts
vector< worker_object > get_all_workers(const optional< bool > is_expired=optional< bool >()) const
get_required_fees_helper(const fee_schedule &_current_fee_schedule, const price &_core_exchange_rate, uint32_t _max_recursion)
vector< extended_asset_object > list_assets(const string &lower_bound_symbol, uint32_t limit) const
Get assets alphabetically by symbol name.
uint64_t get_account_count() const
Get the total number of accounts registered with the blockchain.
vector< fc::variant > get_required_fees(const vector< operation > &ops, const std::string &asset_symbol_or_id) const
For each operation calculate the required fee in the specified asset type.
virtual const object * find(object_id_type id) const override
Definition: index.hpp:332
const vector< optional< operation_history_object > > & get_applied_operations() const
Definition: db_block.cpp:548
chain_property_object get_chain_properties() const
vector< fc::variant > get_required_fees(const vector< operation > &ops, const std::string &asset_id_or_symbol) const
vector< market_trade > get_trade_history(const string &base, const string &quote, fc::time_point_sec start, fc::time_point_sec stop, unsigned limit=100) const
Transfers an amount of one asset from one account to another.
Definition: transfer.hpp:45
object_id_type id
Definition: object.hpp:73
vector< worker_object > get_all_workers(const optional< bool > is_expired=optional< bool >()) const
Get workers.
void to_variant(const flat_set< T, A... > &var, variant &vo, uint32_t _max_depth)
Definition: flat.hpp:105
vector< variant > votes
Definition: api_objects.hpp:65
#define GET_REQUIRED_FEES_MAX_RECURSION
vector< asset > get_named_account_balances(const std::string &name, const flat_set< asset_id_type > &assets) const
Semantically equivalent to get_account_balances.
vector< limit_order_object > get_account_limit_orders(const string &account_name_or_id, const string &base, const string &quote, uint32_t limit, optional< limit_order_id_type > ostart_id, optional< price > ostart_price)
uint64_t get_worker_count() const
Get the total number of workers registered with the blockchain.
flat_set< vote_id_type > votes
Definition: account.hpp:58
account_id_type get_id() const
void handle_object_changed(bool force_notify, bool full_object, const vector< object_id_type > &ids, const flat_set< account_id_type > &impacted_accounts, std::function< const object *(object_id_type id)> find_object)
contains only the public point of an elliptic curve key.
Definition: elliptic.hpp:35
The price struct stores asset prices in the BitShares system.
Definition: asset.hpp:114
optional< signed_block > get_block(uint32_t block_num) const
Retrieve a full, signed block.
optional< account_object > get_account_by_name(string name) const
Get info of an account by name.
fc::variants get_objects(const vector< object_id_type > &ids, optional< bool > subscribe) const
void verify_authority(const vector< operation > &ops, const flat_set< public_key_type > &sigs, const std::function< const authority *(account_id_type)> &get_active, const std::function< const authority *(account_id_type)> &get_owner, const custom_authority_lookup &get_custom, bool allow_non_immediate_owner, bool ignore_custom_operation_required_auths, uint32_t max_recursion=GRAPHENE_MAX_SIG_CHECK_DEPTH, bool allow_committee=false, const flat_set< account_id_type > &active_aprovals=flat_set< account_id_type >(), const flat_set< account_id_type > &owner_approvals=flat_set< account_id_type >())
vector< asset_id_type > assets
Definition: api_objects.hpp:73
fc::static_variant< transfer_operation, limit_order_create_operation, limit_order_cancel_operation, call_order_update_operation, fill_order_operation, account_create_operation, account_update_operation, account_whitelist_operation, account_upgrade_operation, account_transfer_operation, asset_create_operation, asset_update_operation, asset_update_bitasset_operation, asset_update_feed_producers_operation, asset_issue_operation, asset_reserve_operation, asset_fund_fee_pool_operation, asset_settle_operation, asset_global_settle_operation, asset_publish_feed_operation, witness_create_operation, witness_update_operation, proposal_create_operation, proposal_update_operation, proposal_delete_operation, withdraw_permission_create_operation, withdraw_permission_update_operation, withdraw_permission_claim_operation, withdraw_permission_delete_operation, committee_member_create_operation, committee_member_update_operation, committee_member_update_global_parameters_operation, vesting_balance_create_operation, vesting_balance_withdraw_operation, worker_create_operation, custom_operation, assert_operation, balance_claim_operation, override_transfer_operation, transfer_to_blind_operation, blind_transfer_operation, transfer_from_blind_operation, asset_settle_cancel_operation, asset_claim_fees_operation, fba_distribute_operation, bid_collateral_operation, execute_bid_operation, asset_claim_pool_operation, asset_update_issuer_operation, htlc_create_operation, htlc_redeem_operation, htlc_redeemed_operation, htlc_extend_operation, htlc_refund_operation, custom_authority_create_operation, custom_authority_update_operation, custom_authority_delete_operation, ticket_create_operation, ticket_update_operation > operation
Definition: operations.hpp:112
optional< vesting_balance_id_type > cashback_vb
std::map< string, full_account > get_full_accounts(const vector< string > &names_or_ids, optional< bool > subscribe)
std::map< string, full_account > get_full_accounts(const vector< string > &names_or_ids, optional< bool > subscribe=optional< bool >())
Fetch all objects relevant to the specified accounts and optionally subscribe to updates.
time_point_sec head_block_time() const
Definition: db_getter.cpp:64
optional< account_object > get_account_by_name(string name) const
account_id_type lifetime_referrer
The lifetime member at the top of the referral tree. Receives a percentage of referral rewards...
vector< limit_order_object > get_limit_orders(std::string a, std::string b, uint32_t limit) const
Get limit orders in a given market.
account_id_type get_account_id_from_string(const std::string &name_or_id) const
Get account object from a name or ID.
processed_transaction validate_transaction(const signed_transaction &trx)
Definition: db_block.cpp:304
std::function< void(const fc::variant &)> _subscribe_callback
string symbol
Ticker symbol for this asset, i.e. "USD".
This secondary index will allow a reverse lookup of all accounts that a particular key or account is ...
vector< flat_set< account_id_type > > get_key_references(vector< public_key_type > keys) const
Get all accounts that refer to the specified public keys in their owner authority, active authorities or memo key.
vector< asset > get_account_balances(const std::string &account_name_or_id, const flat_set< asset_id_type > &assets) const
optional< htlc_object > get_htlc(htlc_id_type id, optional< bool > subscribe=optional< bool >()) const
Get HTLC object.
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:478
fc::variant set_op_fees(operation &op)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
graphene::chain::database & _db
void subscribe_to_market(std::function< void(const variant &)> callback, const std::string &a, const std::string &b)
Request notification when the active orders in the market between two assets changes.
vector< optional< extended_asset_object > > lookup_asset_symbols(const vector< string > &symbols_or_ids) const
map< string, witness_id_type > lookup_witness_accounts(const string &lower_bound_name, uint32_t limit) const
Get names and IDs for registered witnesses.
vector< call_order_object > get_margin_positions(const std::string account_name_or_id) const
Get all open margin positions of a given account.
map< string, committee_member_id_type > lookup_committee_member_accounts(const string &lower_bound_name, uint32_t limit) const
Get names and IDs for registered committee_members.
vector< proposal_object > get_proposed_transactions(const std::string account_name_or_id) const
return a set of proposed transactions (aka proposals) that the specified account can add approval to ...
vector< vesting_balance_object > get_vesting_balances(const std::string account_name_or_id) const
Return all vesting balance objects owned by an account.
order_book get_order_book(const string &base, const string &quote, unsigned limit=50) const
vector< withdraw_permission_object > get_withdraw_permissions_by_recipient(const std::string account_name_or_id, withdraw_permission_id_type start, uint32_t limit) const
Get non expired withdraw permission objects for a recipient(ex:service provider)
chain_id_type get_chain_id() const
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
const fee_schedule & current_fee_schedule() const
Definition: db_getter.cpp:59
processed_transaction validate_transaction(const signed_transaction &trx) const
std::string get_transaction_hex(const signed_transaction &trx) const
Get a hexdump of the serialized binary form of a transaction.
vector< collateral_bid_object > get_collateral_bids(const std::string &a, uint32_t limit, uint32_t start) const
Get collateral_bid_objects for a given asset.
market_ticker get_ticker(const string &base, const string &quote) const
Returns the ticker for the market assetA:assetB.
extended_asset_object extend_asset(ASSET &&a) const
const T & get_secondary_index() const
Definition: index.hpp:177
optional< htlc_object > get_htlc(htlc_id_type id, optional< bool > subscribe) const
vector< call_order_object > get_margin_positions(const std::string account_id_or_name) const
vector< account_id_type > get_account_references(const std::string account_id_or_name) const
fc::variant_object get_config()
Definition: get_config.cpp:31
vector< flat_set< account_id_type > > get_key_references(vector< public_key_type > key) const
account_statistics_object statistics
Definition: api_objects.hpp:61
dynamic_global_property_object get_dynamic_global_properties() const
Retrieve the current graphene::chain::dynamic_global_property_object.
void subscribe_to_item(const T &item) const
void set_pending_transaction_callback(std::function< void(const variant &signed_transaction_object)> cb)
Register a callback handle which will get notified when a transaction is pushed to database...
vector< force_settlement_object > get_settle_orders_by_account(const std::string &account_name_or_id, force_settlement_id_type start, uint32_t limit) const
vector< asset > get_vested_balances(const vector< balance_id_type > &objs) const
std::string get_transaction_hex(const signed_transaction &trx) const
uint64_t get_committee_count() const
Get the total number of committee registered with the blockchain.
boost::signals2::scoped_connection _new_connection
vector< limit_order_object > get_limit_orders_by_account(const string &account_name_or_id, optional< uint32_t > limit, optional< limit_order_id_type > start_id)
boost::signals2::scoped_connection _applied_block_connection
std::map< std::pair< graphene::chain::asset_id_type, graphene::chain::asset_id_type >, std::vector< fc::variant > > market_queue_type
vector< htlc_object > get_htlc_by_from(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const
fc::variant_object get_config() const
map< uint32_t, optional< block_header > > get_block_header_batch(const vector< uint32_t > block_nums) const
vector< proposal_object > get_proposed_transactions(const std::string account_id_or_name) const
void on_objects_new(const vector< object_id_type > &ids, const flat_set< account_id_type > &impacted_accounts)
tracks the parameters of an assetAll assets have a globally unique symbol name that controls how they...
bool verify_account_authority(const string &account_name_or_id, const flat_set< public_key_type > &signers) const
Verify that the public keys have enough authority to approve an operation for this account...
vector< limit_order_object > limit_orders
Definition: api_objects.hpp:69
typename impl::transform< List, Transformer >::type transform
Transform elements of a typelist.
Definition: typelist.hpp:170
const account_object * get_account_from_string(const std::string &name_or_id, bool throw_if_not_found=true) const
#define dlog(FORMAT,...)
Definition: logger.hpp:100
void broadcast_market_updates(const market_queue_type &queue)
safe< int64_t > share_type
Definition: types.hpp:247
vector< force_settlement_object > get_settle_orders(const std::string &a, uint32_t limit) const
map< string, committee_member_id_type > lookup_committee_member_accounts(const string &lower_bound_name, uint32_t limit) const
const object & get(object_id_type id) const
Definition: index.hpp:111
virtual const object * find(object_id_type id) const override
asset_id_type asset_id
Definition: asset.hpp:39
global_property_object get_global_properties() const
Retrieve the current graphene::chain::global_property_object.
bool verify_authority(const signed_transaction &trx) const
map< string, account_id_type > lookup_accounts(const string &lower_bound_name, uint32_t limit, optional< bool > subscribe) const
account_id_type from
Account to transfer asset from.
Definition: transfer.hpp:54
bitasset_options options
The tunable options for BitAssets are stored in this field.
vector< call_order_object > get_call_orders(const std::string &a, uint32_t limit) const
Get call orders (aka margin positions) for a given asset.
vector< optional< extended_asset_object > > get_assets(const vector< std::string > &asset_symbols_or_ids, optional< bool > subscribe=optional< bool >()) const
Get a list of assets by symbol names or IDs.
set< public_key_type > get_required_signatures(const signed_transaction &trx, const flat_set< public_key_type > &available_keys) const
set< public_key_type > get_required_signatures(const signed_transaction &trx, const flat_set< public_key_type > &available_keys) const
vector< optional< account_object > > get_accounts(const vector< std::string > &account_names_or_ids, optional< bool > subscribe) const
fc::variant_object get_config() const
Retrieve compile-time constants.
account_statistics_id_type statistics
bool is_subscribed_to_item(const T &item) const
asset_id_type get_id() const
vector< force_settlement_object > get_settle_orders(const std::string &a, uint32_t limit) const
Get forced settlement orders in a given asset.
bool is_public_key_registered(string public_key) const
order_book get_order_book(const string &base, const string &quote, unsigned limit=50) const
Returns the order book for the market base:quote.
map< string, witness_id_type > lookup_witness_accounts(const string &lower_bound_name, uint32_t limit) const
Maintains global state information (committee_member list, current fees)This is an implementation det...
void unsubscribe_from_market(const std::string &a, const std::string &b)
Unsubscribe from updates to a given market.
fc::variant set_proposal_create_op_fees(operation &proposal_create_op)
account_id_type registrar
The account that paid the fee to register this account. Receives a percentage of referral rewards...
vector< htlc_object > list_htlcs(const htlc_id_type start, uint32_t limit) const
Get all HTLCs.
fc::optional< committee_member_object > get_committee_member_by_account(const string account_name_or_id) const
Get the committee_member owned by a given account.
vector< optional< account_object > > lookup_account_names(const vector< string > &account_names) const
Get a list of accounts by name.
processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const
used to fetch an individual transaction.
static time_point now()
Definition: time.cpp:13
const chain_id_type & get_chain_id() const
Definition: db_getter.cpp:84
vector< htlc_object > htlcs_from
Definition: api_objects.hpp:76
void cancel_all_subscriptions(bool reset_callback, bool reset_market_subscriptions)
vector< market_ticker > get_top_markets(uint32_t limit) const
vector< optional< account_object > > lookup_account_names(const vector< string > &account_names) const
vector< withdraw_permission_object > withdraws_from
Definition: api_objects.hpp:74
vector< collateral_bid_object > get_collateral_bids(const std::string &asset, uint32_t limit, uint32_t start) const
vector< call_order_object > get_call_orders_by_account(const std::string &account_name_or_id, asset_id_type start, uint32_t limit) const
global_property_object get_global_properties() const
fc::ripemd160 transaction_id_type
Definition: types.hpp:244
optional< signed_transaction > get_recent_transaction_by_id(const transaction_id_type &txid) const
block_id_type head_block_id() const
Definition: db_getter.cpp:74
chain_property_object get_chain_properties() const
Retrieve the graphene::chain::chain_property_object associated with the chain.
vector< vesting_balance_object > get_vesting_balances(const std::string account_id_or_name) const
vector< limit_order_object > get_limit_orders_by_account(const string &account_name_or_id, optional< uint32_t > limit=101, optional< limit_order_id_type > start_id=optional< limit_order_id_type >())
Fetch open limit orders in all markets relevant to the specified account, ordered by ID...
vector< variant > lookup_vote_ids(const vector< vote_id_type > &votes) const
Given a set of votes, return the objects they are voting for.
std::string to_hex(const char *d, uint32_t s)
Definition: hex.cpp:17
tracks information about a committee_member account.A committee_member is responsible for setting blo...
uint64_t get_witness_count() const
Get the total number of witnesses registered with the blockchain.
vector< market_trade > get_trade_history_by_sequence(const string &base, const string &quote, int64_t start, fc::time_point_sec stop, unsigned limit=100) const
fc::optional< witness_object > get_witness_by_account(const std::string account_id_or_name) const
void for_each(T &&t, const account_object &a, seq< Is... >)
Definition: database.hpp:700
vector< blinded_balance_object > get_blinded_balances(const flat_set< commitment_type > &commitments) const
const application_options * _app_options
captures the result of evaluating the operations contained in the transaction
void set_subscribe_callback(std::function< void(const variant &)> cb, bool notify_remove_create)
Register a callback handle which then can be used to subscribe to object database changes...
price max() const
Definition: asset.hpp:130
vector< optional< committee_member_object > > get_committee_members(const vector< committee_member_id_type > &committee_member_ids) const
Get a list of committee_members by ID.
account_id_type referrer
The account credited as referring this account. Receives a percentage of referral rewards...
const asset_bitasset_data_object & bitasset_data(const DB &db) const
vector< asset > get_account_balances(const std::string &account_name_or_id, const flat_set< asset_id_type > &assets) const
Get an account&#39;s balances in various assets.
vector< optional< extended_asset_object > > get_assets(const vector< std::string > &asset_symbols_or_ids, optional< bool > subscribe) const
const graphene::api_helper_indexes::amount_in_collateral_index * amount_in_collateral_index
vector< variant > lookup_vote_ids(const vector< vote_id_type > &votes) const
const IndexType & get_index_type() const
fc::variants get_objects(const vector< object_id_type > &ids, optional< bool > subscribe=optional< bool >()) const
Get the objects corresponding to the provided IDs.
vector< htlc_object > get_htlc_by_from(const std::string account_name_or_id, htlc_id_type start, uint32_t limit) const
Get non expired HTLC objects using the sender account.
boost::signals2::scoped_connection _removed_connection
an offer to sell a amount of a asset at a specified exchange rate by a certain timeThis limit_order_o...
fc::signal< void(const vector< object_id_type > &, const flat_set< account_id_type > &)> new_objects
Definition: database.hpp:209
vector< withdraw_permission_object > get_withdraw_permissions_by_recipient(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit) const
const index_type & indices() const
vector< extended_asset_object > list_assets(const string &lower_bound_symbol, uint32_t limit) const