BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
application.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 #include <graphene/app/api.hpp>
27 #include <graphene/app/plugin.hpp>
28 
33 
35 
38 
41 
42 #include <fc/asio.hpp>
43 #include <fc/io/fstream.hpp>
45 #include <fc/rpc/websocket_api.hpp>
46 #include <fc/crypto/base64.hpp>
47 
48 #include <boost/filesystem/path.hpp>
49 #include <boost/signals2.hpp>
50 #include <boost/range/algorithm/reverse.hpp>
51 #include <boost/algorithm/string.hpp>
52 
53 #include <iostream>
54 
55 #include <fc/log/file_appender.hpp>
56 #include <fc/log/logger.hpp>
57 #include <fc/log/logger_config.hpp>
58 
59 #include <boost/range/adaptor/reversed.hpp>
60 
61 namespace graphene { namespace app {
62 using net::item_hash_t;
63 using net::item_id;
64 using net::message;
65 using net::block_message;
66 using net::trx_message;
67 
68 using chain::block_header;
69 using chain::signed_block_header;
70 using chain::signed_block;
72 
73 using std::vector;
74 
75 namespace bpo = boost::program_options;
76 
77 namespace detail {
78 
80  auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan")));
81  dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key)));
85  initial_state.initial_timestamp = time_point_sec(time_point::now().sec_since_epoch() /
86  initial_state.initial_parameters.block_interval *
87  initial_state.initial_parameters.block_interval);
88  for( uint64_t i = 0; i < initial_state.initial_active_witnesses; ++i )
89  {
90  auto name = "init"+fc::to_string(i);
91  initial_state.initial_accounts.emplace_back(name,
92  nathan_key.get_public_key(),
93  nathan_key.get_public_key(),
94  true);
95  initial_state.initial_committee_candidates.push_back({name});
96  initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key()});
97  }
98 
99  initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key());
100  initial_state.initial_balances.push_back({address(nathan_key.get_public_key()),
103  initial_state.initial_chain_id = fc::sha256::hash( "BOGUS" );
104 
105  return initial_state;
106  }
107 
108 
109 }
110 
111 }}
112 
113 #include "application_impl.hxx"
114 
115 namespace graphene { namespace app { namespace detail {
116 
118 {
119  this->shutdown();
120 }
121 
123 { try {
124  _p2p_network = std::make_shared<net::node>("BitShares Reference Implementation");
125 
126  _p2p_network->load_configuration(data_dir / "p2p");
127  _p2p_network->set_node_delegate(shared_from_this());
128 
129  if( _options->count("seed-node") > 0 )
130  {
131  auto seeds = _options->at("seed-node").as<vector<string>>();
132  _p2p_network->add_seed_nodes(seeds);
133  }
134 
135  if( _options->count("seed-nodes") > 0 )
136  {
137  auto seeds_str = _options->at("seed-nodes").as<string>();
138  auto seeds = fc::json::from_string(seeds_str).as<vector<string>>(2);
139  _p2p_network->add_seed_nodes(seeds);
140  }
141  else
142  {
143  vector<string> seeds = {
144  #include "../egenesis/seed-nodes.txt"
145  };
146  _p2p_network->add_seed_nodes(seeds);
147  }
148 
149  if( _options->count( "p2p-advertise-peer-algorithm" ) > 0 )
150  {
151  std::string algo = _options->at("p2p-advertise-peer-algorithm").as<string>();
152  std::vector<std::string> list;
153  if( algo == "list" && _options->count("p2p-advertise-peer-endpoint") > 0 )
154  list = _options->at("p2p-advertise-peer-endpoint").as<std::vector<std::string>>();
155  else if( algo == "exclude_list" && _options->count("p2p-exclude-peer-endpoint") > 0 )
156  list = _options->at("p2p-exclude-peer-endpoint").as<std::vector<std::string>>();
157  _p2p_network->set_advertise_algorithm( algo, list );
158  }
159 
160  if( _options->count("p2p-endpoint") > 0 )
161  _p2p_network->set_listen_endpoint( fc::ip::endpoint::from_string(_options->at("p2p-endpoint").as<string>()),
162  true );
163  // else try to listen on the default port first, if failed, use a random port
164 
165  if( _options->count("p2p-inbound-endpoint") > 0 )
166  _p2p_network->set_inbound_endpoint( fc::ip::endpoint::from_string(_options->at("p2p-inbound-endpoint")
167  .as<string>()) );
168 
169  if ( _options->count("p2p-accept-incoming-connections") > 0 )
170  _p2p_network->set_accept_incoming_connections( _options->at("p2p-accept-incoming-connections").as<bool>() );
171 
172  if ( _options->count("p2p-connect-to-new-peers") > 0 )
173  _p2p_network->set_connect_to_new_peers( _options->at( "p2p-connect-to-new-peers" ).as<bool>() );
174 
175  _p2p_network->listen_to_p2p_network();
176  fc::ip::endpoint listening_endpoint = _p2p_network->get_actual_listening_endpoint();
177  if( listening_endpoint.port() != 0 )
178  ilog( "Configured p2p node to listen on ${ip}", ("ip", listening_endpoint) );
179  else
180  ilog( "Configured p2p node to not listen for incoming connections" );
181 
182  _p2p_network->connect_to_p2p_network();
184  _chain_db->head_block_id()),
185  std::vector<uint32_t>());
186 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
187 
189 {
190  auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(c, GRAPHENE_NET_MAX_NESTED_OBJECTS);
191  auto login = std::make_shared<graphene::app::login_api>( _self );
192 
193  // Try to extract login information from "Authorization" header if present
194  std::string auth = c->get_request_header("Authorization");
195  if( boost::starts_with(auth, "Basic ") ) {
196 
197  FC_ASSERT( auth.size() > 6 );
198  auto user_pass = fc::base64_decode(auth.substr(6));
199 
200  std::vector<std::string> parts;
201  boost::split( parts, user_pass, boost::is_any_of(":") );
202 
203  FC_ASSERT(parts.size() == 2);
204 
205  const string& username = parts[0];
206  const string& password = parts[1];
207  login->login(username, password);
208  }
209  else
210  login->login("", "");
211 
212  // API set ID 0. Note: changing it may break client applications
213  if( login->is_database_api_allowed() )
214  wsc->register_api(login->database());
215  else
216  wsc->register_api(login->dummy());
217  // API set ID 1. Note: changing it may break client applications
218  wsc->register_api(fc::api<graphene::app::login_api>(login));
219  c->set_session_data( wsc );
220 }
221 
223 { try {
224  if( 0 == _options->count("rpc-endpoint") )
225  return;
226 
227  string proxy_forward_header;
228  if( _options->count("proxy-forwarded-for-header") > 0 )
229  proxy_forward_header = _options->at("proxy-forwarded-for-header").as<string>();
230 
231  _websocket_server = std::make_shared<fc::http::websocket_server>( proxy_forward_header );
232  _websocket_server->on_connection( std::bind(&application_impl::new_connection, this, std::placeholders::_1) );
233 
234  ilog("Configured websocket rpc to listen on ${ip}", ("ip",_options->at("rpc-endpoint").as<string>()));
235  _websocket_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-endpoint").as<string>()) );
236  _websocket_server->start_accept();
237 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
238 
240 { try {
241  if( 0 == _options->count("rpc-tls-endpoint") )
242  return;
243  if( 0 == _options->count("server-pem") )
244  {
245  wlog( "Please specify a server-pem to use rpc-tls-endpoint" );
246  return;
247  }
248 
249  string proxy_forward_header;
250  if( _options->count("proxy-forwarded-for-header") > 0 )
251  proxy_forward_header = _options->at("proxy-forwarded-for-header").as<string>();
252 
253  string password = ( _options->count("server-pem-password") > 0 ) ?
254  _options->at("server-pem-password").as<string>() : "";
255  _websocket_tls_server = std::make_shared<fc::http::websocket_tls_server>(
256  _options->at("server-pem").as<string>(), password, proxy_forward_header );
257  _websocket_tls_server->on_connection( std::bind(&application_impl::new_connection, this, std::placeholders::_1) );
258 
259  ilog("Configured websocket TLS rpc to listen on ${ip}", ("ip",_options->at("rpc-tls-endpoint").as<string>()));
260  _websocket_tls_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-tls-endpoint").as<string>()) );
261  _websocket_tls_server->start_accept();
262 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
263 
264 void application_impl::initialize(const fc::path& data_dir, shared_ptr<boost::program_options::variables_map> options)
265 {
266  _data_dir = data_dir;
267  _options = options;
268 
269  if ( _options->count("io-threads") > 0 )
270  {
271  const uint16_t num_threads = _options->at("io-threads").as<uint16_t>();
273  }
274 
275  if( _options->count("force-validate") > 0 )
276  {
277  ilog( "All transaction signatures will be validated" );
278  _force_validate = true;
279  }
280 
281  if ( _options->count("enable-subscribe-to-all") > 0 )
282  _app_options.enable_subscribe_to_all = _options->at( "enable-subscribe-to-all" ).as<bool>();
283 
284  set_api_limit();
285 
286  if( is_plugin_enabled( "market_history" ) )
288  else
289  ilog("Market history plugin is not enabled");
290 
291  if( is_plugin_enabled( "api_helper_indexes" ) )
293  else
294  ilog("API helper indexes plugin is not enabled");
295 
296  if (_options->count("api-node-info") > 0)
297  _node_info = _options->at("api-node-info").as<string>();
298 
299  if( _options->count("api-access") > 0 )
300  {
301 
302  fc::path api_access_file = _options->at("api-access").as<boost::filesystem::path>();
303 
304  FC_ASSERT( fc::exists(api_access_file),
305  "Failed to load file from ${path}", ("path", api_access_file) );
306 
307  _apiaccess = fc::json::from_file( api_access_file ).as<api_access>( 20 );
308  ilog( "Using api access file from ${path}",
309  ("path", api_access_file) );
310  }
311  else
312  {
313  // TODO: Remove this generous default access policy
314  // when the UI logs in properly
315  _apiaccess = api_access();
316  api_access_info wild_access("*", "*");
317  wild_access.allowed_apis.insert( "database_api" );
318  wild_access.allowed_apis.insert( "network_broadcast_api" );
319  wild_access.allowed_apis.insert( "history_api" );
320  wild_access.allowed_apis.insert( "orders_api" );
321  wild_access.allowed_apis.insert( "custom_operations_api" );
322  _apiaccess.permission_map["*"] = wild_access;
323  }
324 
325  initialize_plugins();
326 }
327 
329  if (_options->count("api-limit-get-account-history-operations") > 0) {
331  _options->at("api-limit-get-account-history-operations").as<uint32_t>();
332  }
333  if(_options->count("api-limit-get-account-history") > 0){
335  _options->at("api-limit-get-account-history").as<uint32_t>();
336  }
337  if(_options->count("api-limit-get-grouped-limit-orders") > 0){
339  _options->at("api-limit-get-grouped-limit-orders").as<uint32_t>();
340  }
341  if(_options->count("api-limit-get-market-history") > 0){
343  _options->at("api-limit-get-market-history").as<uint32_t>();
344  }
345  if(_options->count("api-limit-get-relative-account-history") > 0){
347  _options->at("api-limit-get-relative-account-history").as<uint32_t>();
348  }
349  if(_options->count("api-limit-get-account-history-by-operations") > 0){
351  _options->at("api-limit-get-account-history-by-operations").as<uint32_t>();
352  }
353  if(_options->count("api-limit-get-asset-holders") > 0){
355  _options->at("api-limit-get-asset-holders").as<uint32_t>();
356  }
357  if(_options->count("api-limit-get-key-references") > 0){
359  _options->at("api-limit-get-key-references").as<uint32_t>();
360  }
361  if(_options->count("api-limit-get-htlc-by") > 0) {
363  _options->at("api-limit-get-htlc-by").as<uint32_t>();
364  }
365  if(_options->count("api-limit-get-full-accounts") > 0) {
367  _options->at("api-limit-get-full-accounts").as<uint32_t>();
368  }
369  if(_options->count("api-limit-get-full-accounts-lists") > 0) {
371  _options->at("api-limit-get-full-accounts-lists").as<uint32_t>();
372  }
373  if(_options->count("api-limit-get-full-accounts-subscribe") > 0) {
375  _options->at("api-limit-get-full-accounts-subscribe").as<uint32_t>();
376  }
377  if(_options->count("api-limit-get-top-voters") > 0) {
379  _options->at("api-limit-get-top-voters").as<uint32_t>();
380  }
381  if(_options->count("api-limit-get-call-orders") > 0) {
383  _options->at("api-limit-get-call-orders").as<uint32_t>();
384  }
385  if(_options->count("api-limit-get-settle-orders") > 0) {
387  _options->at("api-limit-get-settle-orders").as<uint32_t>();
388  }
389  if(_options->count("api-limit-get-assets") > 0) {
391  _options->at("api-limit-get-assets").as<uint32_t>();
392  }
393  if(_options->count("api-limit-get-limit-orders") > 0){
395  _options->at("api-limit-get-limit-orders").as<uint32_t>();
396  }
397  if(_options->count("api-limit-get-limit-orders-by-account") > 0){
399  _options->at("api-limit-get-limit-orders-by-account").as<uint32_t>();
400  }
401  if(_options->count("api-limit-get-order-book") > 0){
403  _options->at("api-limit-get-order-book").as<uint32_t>();
404  }
405  if(_options->count("api-limit-list-htlcs") > 0){
407  _options->at("api-limit-list-htlcs").as<uint32_t>();
408  }
409  if(_options->count("api-limit-lookup-accounts") > 0) {
411  _options->at("api-limit-lookup-accounts").as<uint32_t>();
412  }
413  if(_options->count("api-limit-lookup-witness-accounts") > 0) {
415  _options->at("api-limit-lookup-witness-accounts").as<uint32_t>();
416  }
417  if(_options->count("api-limit-lookup-committee-member-accounts") > 0) {
419  _options->at("api-limit-lookup-committee-member-accounts").as<uint32_t>();
420  }
421  if(_options->count("api-limit-lookup-vote-ids") > 0) {
423  _options->at("api-limit-lookup-vote-ids").as<uint32_t>();
424  }
425  if(_options->count("api-limit-get-account-limit-orders") > 0) {
427  _options->at("api-limit-get-account-limit-orders").as<uint32_t>();
428  }
429  if(_options->count("api-limit-get-collateral-bids") > 0) {
431  _options->at("api-limit-get-collateral-bids").as<uint32_t>();
432  }
433  if(_options->count("api-limit-get-top-markets") > 0) {
435  _options->at("api-limit-get-top-markets").as<uint32_t>();
436  }
437  if(_options->count("api-limit-get-trade-history") > 0) {
439  _options->at("api-limit-get-trade-history").as<uint32_t>();
440  }
441  if(_options->count("api-limit-get-trade-history-by-sequence") > 0) {
443  _options->at("api-limit-get-trade-history-by-sequence").as<uint32_t>();
444  }
445  if(_options->count("api-limit-get-withdraw-permissions-by-giver") > 0) {
447  _options->at("api-limit-get-withdraw-permissions-by-giver").as<uint32_t>();
448  }
449  if(_options->count("api-limit-get-withdraw-permissions-by-recipient") > 0) {
451  _options->at("api-limit-get-withdraw-permissions-by-recipient").as<uint32_t>();
452  }
453  if(_options->count("api-limit-get-tickets") > 0) {
455  _options->at("api-limit-get-tickets").as<uint32_t>();
456  }
457  if(_options->count("api-limit-get-liquidity-pools") > 0) {
459  _options->at("api-limit-get-liquidity-pools").as<uint32_t>();
460  }
461  if(_options->count("api-limit-get-liquidity-pool-history") > 0) {
463  _options->at("api-limit-get-liquidity-pool-history").as<uint32_t>();
464  }
465  if(_options->count("api-limit-get-samet-funds") > 0) {
467  _options->at("api-limit-get-samet-funds").as<uint32_t>();
468  }
469  if(_options->count("api-limit-get-credit-offers") > 0) {
471  _options->at("api-limit-get-credit-offers").as<uint32_t>();
472  }
473  if(_options->count("api-limit-get-storage-info") > 0) {
475  _options->at("api-limit-get-storage-info").as<uint32_t>();
476  }
477 }
478 
479 graphene::chain::genesis_state_type application_impl::initialize_genesis_state() const
480 {
481  try {
482  ilog("Initializing database...");
483  if( _options->count("genesis-json") > 0 )
484  {
485  std::string genesis_str;
486  fc::read_file_contents( _options->at("genesis-json").as<boost::filesystem::path>(), genesis_str );
487  auto genesis = fc::json::from_string( genesis_str ).as<graphene::chain::genesis_state_type>( 20 );
488  bool modified_genesis = false;
489  if( _options->count("genesis-timestamp") > 0 )
490  {
492  + genesis.initial_parameters.block_interval
493  + _options->at("genesis-timestamp").as<uint32_t>();
494  genesis.initial_timestamp -= ( genesis.initial_timestamp.sec_since_epoch()
495  % genesis.initial_parameters.block_interval );
496  modified_genesis = true;
497 
498  ilog(
499  "Used genesis timestamp: ${timestamp} (PLEASE RECORD THIS)",
500  ("timestamp", genesis.initial_timestamp.to_iso_string())
501  );
502  }
503  if( _options->count("dbg-init-key") > 0 )
504  {
505  std::string init_key = _options->at( "dbg-init-key" ).as<string>();
506  FC_ASSERT( genesis.initial_witness_candidates.size() >= genesis.initial_active_witnesses );
507  genesis.override_witness_signing_keys( init_key );
508  modified_genesis = true;
509  ilog("Set init witness key to ${init_key}", ("init_key", init_key));
510  }
511  if( modified_genesis )
512  {
513  wlog("WARNING: GENESIS WAS MODIFIED, YOUR CHAIN ID MAY BE DIFFERENT");
514  genesis_str += "BOGUS";
515  }
516  genesis.initial_chain_id = fc::sha256::hash( genesis_str );
517  return genesis;
518  }
519  else
520  {
521  std::string egenesis_json;
523  FC_ASSERT( egenesis_json != "" );
525  auto genesis = fc::json::from_string( egenesis_json ).as<graphene::chain::genesis_state_type>( 20 );
526  genesis.initial_chain_id = fc::sha256::hash( egenesis_json );
527  return genesis;
528  }
529  } FC_CAPTURE_AND_RETHROW() // GCOVR_EXCL_LINE
530 }
531 
532 void application_impl::open_chain_database() const
533 { try {
534  fc::create_directories(_data_dir / "blockchain");
535 
536  if( _options->count("resync-blockchain") > 0 )
537  _chain_db->wipe(_data_dir / "blockchain", true);
538 
539  flat_map<uint32_t,block_id_type> loaded_checkpoints;
540  if( _options->count("checkpoint") > 0 )
541  {
542  auto cps = _options->at("checkpoint").as<vector<string>>();
543  loaded_checkpoints.reserve( cps.size() );
544  for( auto cp : cps )
545  {
546  auto item = fc::json::from_string(cp).as<std::pair<uint32_t,block_id_type> >( 2 );
547  loaded_checkpoints[item.first] = item.second;
548  }
549  }
550  _chain_db->add_checkpoints( loaded_checkpoints );
551 
552  if( _options->count("enable-standby-votes-tracking") > 0 )
553  {
554  _chain_db->enable_standby_votes_tracking( _options->at("enable-standby-votes-tracking").as<bool>() );
555  }
556 
557  if( _options->count("replay-blockchain") > 0 || _options->count("revalidate-blockchain") > 0 )
558  _chain_db->wipe( _data_dir / "blockchain", false );
559 
560  try
561  {
562  // these flags are used in open() only, i. e. during replay
563  uint32_t skip;
564  if( _options->count("revalidate-blockchain") > 0 ) // see also handle_block()
565  {
566  if( !loaded_checkpoints.empty() )
567  wlog( "Warning - revalidate will not validate before last checkpoint" );
568  if( _options->count("force-validate") > 0 )
570  else
572  }
573  else // no revalidate, skip most checks
581 
582  auto genesis_loader = [this](){
583  return initialize_genesis_state();
584  };
585 
586  graphene::chain::detail::with_skip_flags( *_chain_db, skip, [this, &genesis_loader] () {
587  _chain_db->open( _data_dir / "blockchain", genesis_loader, GRAPHENE_CURRENT_DB_VERSION );
588  });
589  }
590  catch( const fc::exception& e )
591  {
592  elog( "Caught exception ${e} in open(), you might want to force a replay", ("e", e.to_detail_string()) );
593  throw;
594  }
595 } FC_LOG_AND_RETHROW() }
596 
598 { try {
599  bool enable_p2p_network = true;
600  if( _options->count("enable-p2p-network") > 0 )
601  enable_p2p_network = _options->at("enable-p2p-network").as<bool>();
602 
603  open_chain_database();
604 
605  startup_plugins();
606 
607  if( enable_p2p_network && _active_plugins.find( "delayed_node" ) == _active_plugins.end() )
608  reset_p2p_node(_data_dir);
609 
612 } FC_LOG_AND_RETHROW() }
613 
615 {
617  auto it = _apiaccess.permission_map.find(username);
618  if( it == _apiaccess.permission_map.end() )
619  {
620  it = _apiaccess.permission_map.find("*");
621  if( it == _apiaccess.permission_map.end() )
622  return result;
623  }
624  return it->second;
625 }
626 
627 void application_impl::set_api_access_info(const string& username, api_access_info&& permissions)
628 {
629  _apiaccess.permission_map.insert(std::make_pair(username, std::move(permissions)));
630 }
631 
632 bool application_impl::is_plugin_enabled(const string& name) const
633 {
634  return !(_active_plugins.find(name) == _active_plugins.end());
635 }
636 
637 /*
638  * If delegate has the item, the network has no need to fetch it.
639  */
641 {
642  try
643  {
644  if( id.item_type == graphene::net::block_message_type )
645  return _chain_db->is_known_block(id.item_hash);
646  else
647  return _chain_db->is_known_transaction(id.item_hash);
648  }
649  FC_CAPTURE_AND_RETHROW( (id) ) // GCOVR_EXCL_LINE
650 }
651 
652 /*
653  * @brief allows the application to validate an item prior to broadcasting to peers.
654  *
655  * @param sync_mode true if the message was fetched through the sync process, false during normal operation
656  * @returns true if this message caused the blockchain to switch forks, false if it did not
657  *
658  * @throws exception if error validating the item, otherwise the item is safe to broadcast on.
659  */
661  std::vector<graphene::net::message_hash_type>& contained_transaction_msg_ids)
662 { try {
663 
664  auto latency = fc::time_point::now() - blk_msg.block.timestamp;
665  if (!sync_mode || blk_msg.block.block_num() % 10000 == 0)
666  {
667  const auto& witness = blk_msg.block.witness(*_chain_db);
668  const auto& witness_account = witness.witness_account(*_chain_db);
669  auto last_irr = _chain_db->get_dynamic_global_properties().last_irreversible_block_num;
670  ilog("Got block: #${n} ${bid} time: ${t} transaction(s): ${x} "
671  "latency: ${l} ms from: ${w} irreversible: ${i} (-${d})",
672  ("t",blk_msg.block.timestamp)
673  ("n", blk_msg.block.block_num())
674  ("bid", blk_msg.block.id())
675  ("x", blk_msg.block.transactions.size())
676  ("l", (latency.count()/1000))
677  ("w",witness_account.name)
678  ("i",last_irr)("d",blk_msg.block.block_num()-last_irr) );
679  }
680  GRAPHENE_ASSERT( latency.count()/1000 > -2500, // 2.5 seconds
681  graphene::net::block_timestamp_in_future_exception,
682  "Rejecting block with timestamp in the future", );
683 
684  try {
685  const uint32_t skip = (_is_block_producer || _force_validate) ?
687  bool result = valve.do_serial( [this,&blk_msg,skip] () {
688  _chain_db->precompute_parallel( blk_msg.block, skip ).wait();
689  }, [this,&blk_msg,skip] () {
690  // TODO: in the case where this block is valid but on a fork that's too old for us to switch to,
691  // you can help the network code out by throwing a block_older_than_undo_history exception.
692  // when the net code sees that, it will stop trying to push blocks from that chain, but
693  // leave that peer connected so that they can get sync blocks from us
694  return _chain_db->push_block( blk_msg.block, skip );
695  });
696 
697  // the block was accepted, so we now know all of the transactions contained in the block
698  if (!sync_mode)
699  {
700  // if we're not in sync mode, there's a chance we will be seeing some transactions
701  // included in blocks before we see the free-floating transaction itself. If that
702  // happens, there's no reason to fetch the transactions, so construct a list of the
703  // transaction message ids we no longer need.
704  // during sync, it is unlikely that we'll see any old
705  contained_transaction_msg_ids.reserve( contained_transaction_msg_ids.size()
706  + blk_msg.block.transactions.size() );
707  for (const processed_transaction& ptrx : blk_msg.block.transactions)
708  {
709  graphene::net::trx_message transaction_message(ptrx);
710  contained_transaction_msg_ids.emplace_back(graphene::net::message(transaction_message).id());
711  }
712  }
713 
714  return result;
715  } catch ( const graphene::chain::unlinkable_block_exception& e ) {
716  // translate to a graphene::net exception
717  elog("Error when pushing block:\n${e}", ("e", e.to_detail_string()));
718  FC_THROW_EXCEPTION( graphene::net::unlinkable_block_exception,
719  "Error when pushing block:\n${e}",
720  ("e", e.to_detail_string()) );
721  } catch( const fc::exception& e ) {
722  elog("Error when pushing block:\n${e}", ("e", e.to_detail_string()));
723  throw;
724  }
725 
726  if( !_is_finished_syncing && !sync_mode )
727  {
728  _is_finished_syncing = true;
729  _self.syncing_finished();
730  }
731 } FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) return false; } // GCOVR_EXCL_LINE
732 
734 { try {
735  static fc::time_point last_call;
736  static int trx_count = 0;
737  ++trx_count;
738  auto now = fc::time_point::now();
739  if( now - last_call > fc::seconds(1) ) {
740  ilog("Got ${c} transactions from network", ("c",trx_count) );
741  last_call = now;
742  trx_count = 0;
743  }
744 
745  _chain_db->precompute_parallel( transaction_message.trx ).wait();
746  _chain_db->push_transaction( transaction_message.trx );
747 } FC_CAPTURE_AND_RETHROW( (transaction_message) ) } // GCOVR_EXCL_LINE
748 
749 void application_impl::handle_message(const message& message_to_process)
750 {
751  // not a transaction, not a block
752  FC_THROW( "Invalid Message Type" );
753 }
754 
756 {
757  uint32_t block_num = block_header::num_from_id(block_id);
758  block_id_type block_id_in_preferred_chain = _chain_db->get_block_id_for_num(block_num);
759  return block_id == block_id_in_preferred_chain;
760 }
761 
762 /*
763  * Assuming all data elements are ordered in some way, this method should
764  * return up to limit ids that occur *after* the last ID in synopsis that
765  * we recognize.
766  *
767  * On return, remaining_item_count will be set to the number of items
768  * in our blockchain after the last item returned in the result,
769  * or 0 if the result contains the last item in the blockchain
770  */
771 std::vector<item_hash_t> application_impl::get_block_ids(const std::vector<item_hash_t>& blockchain_synopsis,
772  uint32_t& remaining_item_count,
773  uint32_t limit)
774 { try {
775  vector<block_id_type> result;
776  remaining_item_count = 0;
777  if( _chain_db->head_block_num() == 0 )
778  return result;
779 
780  result.reserve(limit);
781  block_id_type last_known_block_id;
782 
783  if (blockchain_synopsis.empty() ||
784  (blockchain_synopsis.size() == 1 && blockchain_synopsis[0] == block_id_type()))
785  {
786  // peer has sent us an empty synopsis meaning they have no blocks.
787  // A bug in old versions would cause them to send a synopsis containing block 000000000
788  // when they had an empty blockchain, so pretend they sent the right thing here.
789 
790  // do nothing, leave last_known_block_id set to zero
791  }
792  else
793  {
794  bool found_a_block_in_synopsis = false;
795  for (const item_hash_t& block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis))
796  if (block_id_in_synopsis == block_id_type() ||
797  (_chain_db->is_known_block(block_id_in_synopsis) && is_included_block(block_id_in_synopsis)))
798  {
799  last_known_block_id = block_id_in_synopsis;
800  found_a_block_in_synopsis = true;
801  break;
802  }
803  if (!found_a_block_in_synopsis)
804  FC_THROW_EXCEPTION( graphene::net::peer_is_on_an_unreachable_fork,
805  "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis" );
806  }
807  for( uint32_t num = block_header::num_from_id(last_known_block_id);
808  num <= _chain_db->head_block_num() && result.size() < limit;
809  ++num )
810  if( num > 0 )
811  result.push_back(_chain_db->get_block_id_for_num(num));
812 
813  if( !result.empty() && block_header::num_from_id(result.back()) < _chain_db->head_block_num() )
814  remaining_item_count = _chain_db->head_block_num() - block_header::num_from_id(result.back());
815 
816  return result;
817 } FC_CAPTURE_AND_RETHROW( (blockchain_synopsis)(remaining_item_count)(limit) ) } // GCOVR_EXCL_LINE
818 
819 /*
820  * Given the hash of the requested data, fetch the body.
821  */
823 { try {
824  // ilog("Request for item ${id}", ("id", id));
825  if( id.item_type == graphene::net::block_message_type )
826  {
827  auto opt_block = _chain_db->fetch_block_by_id(id.item_hash);
828  if( !opt_block )
829  elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}",
830  ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block_header::num_from_id(id.item_hash))));
831  FC_ASSERT( opt_block.valid() );
832  // ilog("Serving up block #${num}", ("num", opt_block->block_num()));
833  return block_message(std::move(*opt_block));
834  }
835  return trx_message( _chain_db->get_recent_transaction( id.item_hash ) );
836 } FC_CAPTURE_AND_RETHROW( (id) ) } // GCOVR_EXCL_LINE
837 
839 {
840  return _chain_db->get_chain_id();
841 }
842 
843 /*
844  * Returns a synopsis of the blockchain used for syncing. This consists of a list of
845  * block hashes at intervals exponentially increasing towards the genesis block.
846  * When syncing to a peer, the peer uses this data to determine if we're on the same
847  * fork as they are, and if not, what blocks they need to send us to get us on their
848  * fork.
849  *
850  * In the over-simplified case, this is a straighforward synopsis of our current
851  * preferred blockchain; when we first connect up to a peer, this is what we will be sending.
852  * It looks like this:
853  * If the blockchain is empty, it will return the empty list.
854  * If the blockchain has one block, it will return a list containing just that block.
855  * If it contains more than one block:
856  * the first element in the list will be the hash of the highest numbered block that
857  * we cannot undo
858  * the second element will be the hash of an item at the half way point in the undoable
859  * segment of the blockchain
860  * the third will be ~3/4 of the way through the undoable segment of the block chain
861  * the fourth will be at ~7/8...
862  * &c.
863  * the last item in the list will be the hash of the most recent block on our preferred chain
864  * so if the blockchain had 26 blocks labeled a - z, the synopsis would be:
865  * a n u x z
866  * the idea being that by sending a small (<30) number of block ids, we can summarize a huge
867  * blockchain. The block ids are more dense near the end of the chain where because we are
868  * more likely to be almost in sync when we first connect, and forks are likely to be short.
869  * If the peer we're syncing with in our example is on a fork that started at block 'v',
870  * then they will reply to our synopsis with a list of all blocks starting from block 'u',
871  * the last block they know that we had in common.
872  *
873  * In the real code, there are several complications.
874  *
875  * First, as an optimization, we don't usually send a synopsis of the entire blockchain, we
876  * send a synopsis of only the segment of the blockchain that we have undo data for. If their
877  * fork doesn't build off of something in our undo history, we would be unable to switch, so there's
878  * no reason to fetch the blocks.
879  *
880  * Second, when a peer replies to our initial synopsis and gives us a list of the blocks they think
881  * we are missing, they only send a chunk of a few thousand blocks at once. After we get those
882  * block ids, we need to request more blocks by sending another synopsis (we can't just say "send me
883  * the next 2000 ids" because they may have switched forks themselves and they don't track what
884  * they've sent us). For faster performance, we want to get a fairly long list of block ids first,
885  * then start downloading the blocks.
886  * The peer doesn't handle these follow-up block id requests any different from the initial request;
887  * it treats the synopsis we send as our blockchain and bases its response entirely off that. So to
888  * get the response we want (the next chunk of block ids following the last one they sent us, or,
889  * failing that, the shortest fork off of the last list of block ids they sent), we need to construct
890  * a synopsis as if our blockchain was made up of:
891  * 1. the blocks in our block chain up to the fork point (if there is a fork) or the head block (if no fork)
892  * 2. the blocks we've already pushed from their fork (if there's a fork)
893  * 3. the block ids they've previously sent us
894  * Segment 3 is handled in the p2p code, it just tells us the number of blocks it has (in
895  * number_of_blocks_after_reference_point) so we can leave space in the synopsis for them.
896  * We're responsible for constructing the synopsis of Segments 1 and 2 from our active blockchain and
897  * fork database. The reference_point parameter is the last block from that peer that has been
898  * successfully pushed to the blockchain, so that tells us whether the peer is on a fork or on
899  * the main chain.
900  */
901 std::vector<item_hash_t> application_impl::get_blockchain_synopsis(const item_hash_t& reference_point,
902  uint32_t number_of_blocks_after_reference_point)
903 { try {
904  std::vector<item_hash_t> synopsis;
905  synopsis.reserve(30);
906  uint32_t high_block_num;
907  uint32_t non_fork_high_block_num;
908  uint32_t low_block_num = _chain_db->last_non_undoable_block_num();
909  std::vector<block_id_type> fork_history;
910 
911  if (reference_point != item_hash_t())
912  {
913  // the node is asking for a summary of the block chain up to a specified
914  // block, which may or may not be on a fork
915  // for now, assume it's not on a fork
916  if (is_included_block(reference_point))
917  {
918  // reference_point is a block we know about and is on the main chain
919  uint32_t reference_point_block_num = block_header::num_from_id(reference_point);
920  assert(reference_point_block_num > 0);
921  high_block_num = reference_point_block_num;
922  non_fork_high_block_num = high_block_num;
923 
924  if (reference_point_block_num < low_block_num)
925  {
926  // we're on the same fork (at least as far as reference_point) but we've passed
927  // reference point and could no longer undo that far if we diverged after that
928  // block. This should probably only happen due to a race condition where
929  // the network thread calls this function, and then immediately pushes a bunch of blocks,
930  // then the main thread finally processes this function.
931  // with the current framework, there's not much we can do to tell the network
932  // thread what our current head block is, so we'll just pretend that
933  // our head is actually the reference point.
934  // this *may* enable us to fetch blocks that we're unable to push, but that should
935  // be a rare case (and correctly handled)
936  low_block_num = reference_point_block_num;
937  }
938  }
939  else
940  {
941  // block is a block we know about, but it is on a fork
942  try
943  {
944  fork_history = _chain_db->get_block_ids_on_fork(reference_point);
945  // returns a vector where the last element is the common ancestor with the preferred chain,
946  // and the first element is the reference point you passed in
947  assert(fork_history.size() >= 2);
948 
949  if( fork_history.front() != reference_point )
950  {
951  edump( (fork_history)(reference_point) );
952  assert(fork_history.front() == reference_point);
953  }
954  block_id_type last_non_fork_block = fork_history.back();
955  fork_history.pop_back(); // remove the common ancestor
956  boost::reverse(fork_history);
957 
958  if (last_non_fork_block == block_id_type()) // if the fork goes all the way back to genesis (does graphene's fork db allow this?)
959  non_fork_high_block_num = 0;
960  else
961  non_fork_high_block_num = block_header::num_from_id(last_non_fork_block);
962 
963  high_block_num = non_fork_high_block_num + fork_history.size();
964  assert(high_block_num == block_header::num_from_id(fork_history.back()));
965  }
966  catch (const fc::exception& e)
967  {
968  // unable to get fork history for some reason. maybe not linked?
969  // we can't return a synopsis of its chain
970  elog( "Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}",
971  ("hash", reference_point)("exception", e) );
972  throw;
973  }
974  if (non_fork_high_block_num < low_block_num)
975  {
976  wlog("Unable to generate a usable synopsis because the peer we're generating it for forked too long ago "
977  "(our chains diverge after block #${non_fork_high_block_num} but only undoable to block #${low_block_num})",
978  ("low_block_num", low_block_num)
979  ("non_fork_high_block_num", non_fork_high_block_num));
980  FC_THROW_EXCEPTION(graphene::net::block_older_than_undo_history, "Peer is are on a fork I'm unable to switch to");
981  }
982  }
983  }
984  else
985  {
986  // no reference point specified, summarize the whole block chain
987  high_block_num = _chain_db->head_block_num();
988  non_fork_high_block_num = high_block_num;
989  if (high_block_num == 0)
990  return synopsis; // we have no blocks
991  }
992 
993  if( low_block_num == 0)
994  low_block_num = 1;
995 
996  // at this point:
997  // low_block_num is the block before the first block we can undo,
998  // non_fork_high_block_num is the block before the fork (if the peer is on a fork, or otherwise it is the same as high_block_num)
999  // high_block_num is the block number of the reference block, or the end of the chain if no reference provided
1000 
1001  // true_high_block_num is the ending block number after the network code appends any item ids it
1002  // knows about that we don't
1003  uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point;
1004  do
1005  {
1006  // for each block in the synopsis, figure out where to pull the block id from.
1007  // if it's <= non_fork_high_block_num, we grab it from the main blockchain;
1008  // if it's not, we pull it from the fork history
1009  if (low_block_num <= non_fork_high_block_num)
1010  synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num));
1011  else
1012  synopsis.push_back(fork_history[low_block_num - non_fork_high_block_num - 1]);
1013  low_block_num += (true_high_block_num - low_block_num + 2) / 2;
1014  }
1015  while (low_block_num <= high_block_num);
1016 
1017  //idump((synopsis));
1018  return synopsis;
1019 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
1020 
1021 /*
1022  * Call this after the call to handle_message succeeds.
1023  *
1024  * @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
1025  * @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
1026  * After `item_count` more calls to handle_item(), the node will be in sync
1027  */
1028 void application_impl::sync_status(uint32_t item_type, uint32_t item_count)
1029 {
1030  // any status reports to GUI go here
1031 }
1032 
1033 /*
1034  * Call any time the number of connected peers changes.
1035  */
1037 {
1038  // any status reports to GUI go here
1039 }
1040 
1042 { try {
1043  return block_header::num_from_id(block_id);
1044 } FC_CAPTURE_AND_RETHROW( (block_id) ) } // GCOVR_EXCL_LINE
1045 
1046 /*
1047  * Returns the time a block was produced (if block_id = 0, returns genesis time).
1048  * If we don't know about the block, returns time_point_sec::min()
1049  */
1051 { try {
1052  auto opt_block = _chain_db->fetch_block_by_id( block_id );
1053  if( opt_block.valid() ) return opt_block->timestamp;
1054  return fc::time_point_sec::min();
1055 } FC_CAPTURE_AND_RETHROW( (block_id) ) } // GCOVR_EXCL_LINE
1056 
1058 {
1059  return _chain_db->head_block_id();
1060 }
1061 
1063 {
1064  return 0; // there are no forks in graphene
1065 }
1066 
1067 void application_impl::error_encountered(const std::string& message, const fc::oexception& error)
1068 {
1069  // notify GUI or something cool
1070 }
1071 
1073 {
1074  FC_ASSERT( _chain_db, "Chain database is not operational" );
1075  return _chain_db->get_global_properties().parameters.block_interval;
1076 }
1077 
1078 void application_impl::shutdown()
1079 {
1080  ilog( "Shutting down application" );
1081  if( _websocket_tls_server )
1082  _websocket_tls_server.reset();
1083  if( _websocket_server )
1084  _websocket_server.reset();
1085  // TODO wait until all connections are closed and messages handled?
1086 
1087  // plugins E.G. witness_plugin may send data to p2p network, so shutdown them first
1088  ilog( "Shutting down plugins" );
1089  shutdown_plugins();
1090 
1091  if( _p2p_network )
1092  {
1093  ilog( "Disconnecting from P2P network" );
1094  // FIXME wait() is called in close() but it doesn't block this thread
1095  _p2p_network->close();
1096  _p2p_network.reset();
1097  }
1098  else
1099  ilog( "P2P network is disabled" );
1100 
1101  if( _chain_db )
1102  {
1103  ilog( "Closing chain database" );
1104  _chain_db->close();
1105  _chain_db.reset();
1106  }
1107  else
1108  ilog( "Chain database is not open" );
1109 }
1110 
1111 void application_impl::enable_plugin( const string& name )
1112 {
1113  FC_ASSERT(_available_plugins[name], "Unknown plugin '" + name + "'");
1114  _active_plugins[name] = _available_plugins[name];
1115 }
1116 
1117 void application_impl::initialize_plugins() const
1118 {
1119  for( const auto& entry : _active_plugins )
1120  {
1121  ilog( "Initializing plugin ${name}", ( "name", entry.second->plugin_name() ) );
1122  entry.second->plugin_initialize( *_options );
1123  ilog( "Initialized plugin ${name}", ( "name", entry.second->plugin_name() ) );
1124  }
1125 }
1126 
1127 void application_impl::startup_plugins() const
1128 {
1129  for( const auto& entry : _active_plugins )
1130  {
1131  ilog( "Starting plugin ${name}", ( "name", entry.second->plugin_name() ) );
1132  entry.second->plugin_startup();
1133  ilog( "Started plugin ${name}", ( "name", entry.second->plugin_name() ) );
1134  }
1135 }
1136 
1137 void application_impl::shutdown_plugins() const
1138 {
1139  for( const auto& entry : _active_plugins )
1140  {
1141  ilog( "Stopping plugin ${name}", ( "name", entry.second->plugin_name() ) );
1142  entry.second->plugin_shutdown();
1143  ilog( "Stopped plugin ${name}", ( "name", entry.second->plugin_name() ) );
1144  }
1145 }
1146 
1147 void application_impl::add_available_plugin(std::shared_ptr<graphene::app::abstract_plugin> p)
1148 {
1149  _available_plugins[p->plugin_name()] = p;
1150 }
1151 
1152 void application_impl::set_block_production(bool producing_blocks)
1153 {
1154  _is_block_producer = producing_blocks;
1155 }
1156 
1157 } } } // namespace graphene namespace app namespace detail
1158 
1159 namespace graphene { namespace app {
1160 
1162  : my(std::make_shared<detail::application_impl>(*this))
1163 {
1164  //nothing else to do
1165 }
1166 
1168 {
1169  ilog("Application quitting");
1170  my->shutdown();
1171 }
1172 
1173 void application::set_program_options(boost::program_options::options_description& command_line_options,
1174  boost::program_options::options_description& configuration_file_options) const
1175 {
1176  const auto& default_opts = application_options::get_default();
1177  configuration_file_options.add_options()
1178  ("enable-p2p-network", bpo::value<bool>()->implicit_value(true),
1179  "Whether to enable P2P network (default: true). Note: if delayed_node plugin is enabled, "
1180  "this option will be ignored and P2P network will always be disabled.")
1181  ("p2p-accept-incoming-connections", bpo::value<bool>()->implicit_value(true),
1182  "Whether to accept incoming P2P connections (default: true)")
1183  ("p2p-endpoint", bpo::value<string>(),
1184  "The endpoint (local IP address:port) on which the node will listen for P2P connections. "
1185  "Specify 0.0.0.0 as address to listen on all IP addresses")
1186  ("p2p-inbound-endpoint", bpo::value<string>(),
1187  "The endpoint (external IP address:port) that other P2P peers should connect to. "
1188  "If the address is unknown or dynamic, specify 0.0.0.0")
1189  ("p2p-connect-to-new-peers", bpo::value<bool>()->implicit_value(true),
1190  "Whether the node will connect to new P2P peers advertised by other peers (default: true)")
1191  ("p2p-advertise-peer-algorithm", bpo::value<string>()->implicit_value("all"),
1192  "Determines which P2P peers are advertised in response to address requests from other peers. "
1193  "Algorithms: 'all', 'nothing', 'list', exclude_list'. (default: all)")
1194  ("p2p-advertise-peer-endpoint", bpo::value<vector<string>>()->composing(),
1195  "The endpoint (IP address:port) of the P2P peer to advertise, only takes effect when algorithm "
1196  "is 'list' (may specify multiple times)")
1197  ("p2p-exclude-peer-endpoint", bpo::value<vector<string>>()->composing(),
1198  "The endpoint (IP address:port) of the P2P peer to not advertise, only takes effect when algorithm "
1199  "is 'exclude_list' (may specify multiple times)")
1200  ("seed-node,s", bpo::value<vector<string>>()->composing(),
1201  "The endpoint (IP address:port) of the P2P peer to connect to on startup (may specify multiple times)")
1202  ("seed-nodes", bpo::value<string>()->composing(),
1203  "JSON array of P2P peers to connect to on startup")
1204  ("checkpoint,c", bpo::value<vector<string>>()->composing(),
1205  "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.")
1206  ("rpc-endpoint", bpo::value<string>()->implicit_value("127.0.0.1:8090"),
1207  "Endpoint for websocket RPC to listen on")
1208  ("rpc-tls-endpoint", bpo::value<string>()->implicit_value("127.0.0.1:8089"),
1209  "Endpoint for TLS websocket RPC to listen on")
1210  ("server-pem,p", bpo::value<string>()->implicit_value("server.pem"),
1211  "The TLS certificate file for this server")
1212  ("server-pem-password,P", bpo::value<string>()->implicit_value(""), "Password for this certificate")
1213  ("proxy-forwarded-for-header", bpo::value<string>()->implicit_value("X-Forwarded-For-Client"),
1214  "A HTTP header similar to X-Forwarded-For (XFF), used by the RPC server to extract clients' address info, "
1215  "usually added by a trusted reverse proxy")
1216  ("genesis-json", bpo::value<boost::filesystem::path>(), "File to read Genesis State from")
1217  ("dbg-init-key", bpo::value<string>(),
1218  "Block signing key to use for init witnesses, overrides genesis file, for debug")
1219  ("api-node-info", bpo::value<string>(),
1220  "A string defined by the node operator, which can be retrieved via the login_api::get_info API")
1221  ("api-access", bpo::value<boost::filesystem::path>(), "JSON file specifying API permissions")
1222  ("io-threads", bpo::value<uint16_t>()->implicit_value(0),
1223  "Number of IO threads, default to 0 for auto-configuration")
1224  ("enable-subscribe-to-all", bpo::value<bool>()->implicit_value(true),
1225  "Whether allow API clients to subscribe to universal object creation and removal events")
1226  ("enable-standby-votes-tracking", bpo::value<bool>()->implicit_value(true),
1227  "Whether to enable tracking of votes of standby witnesses and committee members. "
1228  "Set it to true to provide accurate data to API clients, set to false for slightly better performance.")
1229  ("api-limit-get-account-history-operations",
1230  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_account_history_operations),
1231  "For history_api::get_account_history_operations to set max limit value")
1232  ("api-limit-get-account-history",
1233  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_account_history),
1234  "For history_api::get_account_history to set max limit value")
1235  ("api-limit-get-grouped-limit-orders",
1236  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_grouped_limit_orders),
1237  "For orders_api::get_grouped_limit_orders to set max limit value")
1238  ("api-limit-get-market-history",
1239  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_market_history),
1240  "Maximum number of records to return for the history_api::get_market_history API")
1241  ("api-limit-get-relative-account-history",
1242  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_relative_account_history),
1243  "For history_api::get_relative_account_history to set max limit value")
1244  ("api-limit-get-account-history-by-operations",
1245  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_account_history_by_operations),
1246  "For history_api::get_account_history_by_operations to set max limit value")
1247  ("api-limit-get-asset-holders",
1248  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_asset_holders),
1249  "For asset_api::get_asset_holders to set max limit value")
1250  ("api-limit-get-key-references",
1251  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_key_references),
1252  "For database_api_impl::get_key_references to set max limit value")
1253  ("api-limit-get-htlc-by",
1254  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_htlc_by),
1255  "For database_api_impl::get_htlc_by_from and get_htlc_by_to to set max limit value")
1256  ("api-limit-get-full-accounts",
1257  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_full_accounts),
1258  "For database_api_impl::get_full_accounts to set max accounts to query at once")
1259  ("api-limit-get-full-accounts-lists",
1260  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_full_accounts_lists),
1261  "For database_api_impl::get_full_accounts to set max items to return in the lists")
1262  ("api-limit-get-full-accounts-subscribe",
1263  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_full_accounts_subscribe),
1264  "Maximum number of accounts allowed to subscribe per connection with the get_full_accounts API")
1265  ("api-limit-get-top-voters",
1266  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_top_voters),
1267  "For database_api_impl::get_top_voters to set max limit value")
1268  ("api-limit-get-call-orders",
1269  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_call_orders),
1270  "For database_api_impl::get_call_orders and get_call_orders_by_account to set max limit value")
1271  ("api-limit-get-settle-orders",
1272  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_settle_orders),
1273  "For database_api_impl::get_settle_orders and get_settle_orders_by_account to set max limit value")
1274  ("api-limit-get-assets",
1275  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_assets),
1276  "For database_api_impl::list_assets and get_assets_by_issuer to set max limit value")
1277  ("api-limit-get-limit-orders",
1278  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_limit_orders),
1279  "For database_api_impl::get_limit_orders to set max limit value")
1280  ("api-limit-get-limit-orders-by-account",
1281  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_limit_orders_by_account),
1282  "For database_api_impl::get_limit_orders_by_account to set max limit value")
1283  ("api-limit-get-order-book",
1284  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_order_book),
1285  "For database_api_impl::get_order_book to set max limit value")
1286  ("api-limit-list-htlcs",
1287  bpo::value<uint32_t>()->default_value(default_opts.api_limit_list_htlcs),
1288  "For database_api_impl::list_htlcs to set max limit value")
1289  ("api-limit-lookup-accounts",
1290  bpo::value<uint32_t>()->default_value(default_opts.api_limit_lookup_accounts),
1291  "For database_api_impl::lookup_accounts to set max limit value")
1292  ("api-limit-lookup-witness-accounts",
1293  bpo::value<uint32_t>()->default_value(default_opts.api_limit_lookup_witness_accounts),
1294  "For database_api_impl::lookup_witness_accounts to set max limit value")
1295  ("api-limit-lookup-committee-member-accounts",
1296  bpo::value<uint32_t>()->default_value(default_opts.api_limit_lookup_committee_member_accounts),
1297  "For database_api_impl::lookup_committee_member_accounts to set max limit value")
1298  ("api-limit-lookup-vote-ids",
1299  bpo::value<uint32_t>()->default_value(default_opts.api_limit_lookup_vote_ids),
1300  "For database_api_impl::lookup_vote_ids to set max limit value")
1301  ("api-limit-get-account-limit-orders",
1302  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_account_limit_orders),
1303  "For database_api_impl::get_account_limit_orders to set max limit value")
1304  ("api-limit-get-collateral-bids",
1305  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_collateral_bids),
1306  "For database_api_impl::get_collateral_bids to set max limit value")
1307  ("api-limit-get-top-markets",
1308  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_top_markets),
1309  "For database_api_impl::get_top_markets to set max limit value")
1310  ("api-limit-get-trade-history",
1311  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_trade_history),
1312  "For database_api_impl::get_trade_history to set max limit value")
1313  ("api-limit-get-trade-history-by-sequence",
1314  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_trade_history_by_sequence),
1315  "For database_api_impl::get_trade_history_by_sequence to set max limit value")
1316  ("api-limit-get-withdraw-permissions-by-giver",
1317  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_withdraw_permissions_by_giver),
1318  "For database_api_impl::get_withdraw_permissions_by_giver to set max limit value")
1319  ("api-limit-get-withdraw-permissions-by-recipient",
1320  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_withdraw_permissions_by_recipient),
1321  "For database_api_impl::get_withdraw_permissions_by_recipient to set max limit value")
1322  ("api-limit-get-tickets",
1323  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_tickets),
1324  "Set maximum limit value for database APIs which query for tickets")
1325  ("api-limit-get-liquidity-pools",
1326  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_liquidity_pools),
1327  "Set maximum limit value for database APIs which query for liquidity pools")
1328  ("api-limit-get-liquidity-pool-history",
1329  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_liquidity_pool_history),
1330  "Set maximum limit value for APIs which query for history of liquidity pools")
1331  ("api-limit-get-samet-funds",
1332  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_samet_funds),
1333  "Set maximum limit value for database APIs which query for SameT Funds")
1334  ("api-limit-get-credit-offers",
1335  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_credit_offers),
1336  "Set maximum limit value for database APIs which query for credit offers or credit deals")
1337  ("api-limit-get-storage-info",
1338  bpo::value<uint32_t>()->default_value(default_opts.api_limit_get_storage_info),
1339  "Set maximum limit value for APIs which query for account storage info")
1340  ;
1341  command_line_options.add(configuration_file_options);
1342  command_line_options.add_options()
1343  ("replay-blockchain", "Rebuild object graph by replaying all blocks without validation")
1344  ("revalidate-blockchain", "Rebuild object graph by replaying all blocks with full validation")
1345  ("resync-blockchain", "Delete all blocks and re-sync with network from scratch")
1346  ("force-validate", "Force validation of all transactions during normal operation")
1347  ("genesis-timestamp", bpo::value<uint32_t>(),
1348  "Replace timestamp from genesis.json with current time plus this many seconds (experts only!)")
1349  ;
1350  command_line_options.add(_cli_options);
1351  configuration_file_options.add(_cfg_options);
1352 }
1353 
1354 void application::initialize(const fc::path& data_dir,
1355  std::shared_ptr<boost::program_options::variables_map> options) const
1356 {
1357  ilog( "Initializing application" );
1358  my->initialize( data_dir, options );
1359  ilog( "Done initializing application" );
1360 }
1361 
1363 {
1364  try {
1365  ilog( "Starting up application" );
1366  my->startup();
1367  ilog( "Done starting up application" );
1368  } catch ( const fc::exception& e ) {
1369  elog( "${e}", ("e",e.to_detail_string()) );
1370  throw;
1371  } catch ( ... ) {
1372  elog( "unexpected exception" );
1373  throw;
1374  }
1375 }
1376 
1378 {
1379  try {
1380  my->set_api_limit();
1381  } catch ( const fc::exception& e ) {
1382  elog( "${e}", ("e",e.to_detail_string()) );
1383  throw;
1384  } catch ( ... ) {
1385  elog( "unexpected exception" );
1386  throw;
1387  }
1388 }
1389 std::shared_ptr<abstract_plugin> application::get_plugin(const string& name) const
1390 {
1391  return my->_active_plugins[name];
1392 }
1393 
1394 bool application::is_plugin_enabled(const string& name) const
1395 {
1396  return my->is_plugin_enabled(name);
1397 }
1398 
1400 {
1401  return my->_p2p_network;
1402 }
1403 
1404 std::shared_ptr<chain::database> application::chain_database() const
1405 {
1406  return my->_chain_db;
1407 }
1408 
1409 void application::set_block_production(bool producing_blocks)
1410 {
1411  my->set_block_production(producing_blocks);
1412 }
1413 
1415 {
1416  return my->get_api_access_info( username );
1417 }
1418 
1419 void application::set_api_access_info(const string& username, api_access_info&& permissions)
1420 {
1421  my->set_api_access_info(username, std::move(permissions));
1422 }
1423 
1425 {
1426  return my->_is_finished_syncing;
1427 }
1428 
1429 void application::enable_plugin(const string& name) const
1430 {
1431  my->enable_plugin(name);
1432 }
1433 
1434 void application::add_available_plugin(std::shared_ptr<graphene::app::abstract_plugin> p) const
1435 {
1436  my->add_available_plugin(p);
1437 }
1438 
1440 {
1441  return my->_app_options;
1442 }
1443 
1444 const string& application::get_node_info() const
1445 {
1446  return my->_node_info;
1447 }
1448 
1449 // namespace detail
1450 } }
1451 
GRAPHENE_MAX_SHARE_SUPPLY
constexpr int64_t GRAPHENE_MAX_SHARE_SUPPLY(1000000000000000LL)
graphene::app::application_options::api_limit_get_asset_holders
uint32_t api_limit_get_asset_holders
Definition: application.hpp:56
graphene::chain::database::skip_transaction_signatures
@ skip_transaction_signatures
used by non-witness nodes
Definition: database.hpp:81
graphene::net::block_message
Definition: core_messages.hpp:104
FC_CAPTURE_AND_RETHROW
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
graphene::app::application::set_api_access_info
void set_api_access_info(const string &username, api_access_info &&permissions)
Definition: application.cpp:1419
genesis_state.hpp
graphene::chain::database::skip_tapos_check
@ skip_tapos_check
used while reindexing – note this skips expiration check too
Definition: database.hpp:84
graphene::app::detail::application_impl::handle_transaction
void handle_transaction(const graphene::net::trx_message &transaction_message) override
Called when a new transaction comes in from the network.
Definition: application.cpp:733
graphene::app::detail::application_impl::error_encountered
void error_encountered(const std::string &message, const fc::oexception &error) override
Definition: application.cpp:1067
graphene::app::detail::application_impl::set_block_production
void set_block_production(bool producing_blocks)
Definition: application.cpp:1152
wlog
#define wlog(FORMAT,...)
Definition: logger.hpp:123
graphene::app::application::get_node_info
const string & get_node_info() const
Definition: application.cpp:1444
fc::exception
Used to generate a useful error report when an exception is thrown.
Definition: exception.hpp:56
graphene::app::application_options::api_limit_get_collateral_bids
uint32_t api_limit_get_collateral_bids
Definition: application.hpp:69
fc::to_string
std::string to_string(double)
Definition: string.cpp:73
graphene::app::application_options::api_limit_lookup_vote_ids
uint32_t api_limit_lookup_vote_ids
Definition: application.hpp:73
graphene::chain::genesis_state_type::initial_committee_candidates
vector< initial_committee_member_type > initial_committee_candidates
Definition: genesis_state.hpp:113
graphene::app::application::set_api_limit
void set_api_limit()
Definition: application.cpp:1377
graphene::app::application_options::api_limit_get_tickets
uint32_t api_limit_get_tickets
Definition: application.hpp:78
websocket_api.hpp
worker_evaluator.hpp
graphene::chain::detail::with_skip_flags
void with_skip_flags(database &db, uint32_t skip_flags, Lambda callback)
Definition: db_with.hpp:113
graphene::chain::genesis_state_type::initial_witness_candidates
vector< initial_witness_type > initial_witness_candidates
Definition: genesis_state.hpp:112
graphene::utilities::key_to_wif
std::string key_to_wif(const fc::sha256 &private_secret)
Definition: key_conversion.cpp:30
graphene::net::block_message_type
@ block_message_type
Definition: core_messages.hpp:69
graphene::app::application_options::api_limit_get_samet_funds
uint32_t api_limit_get_samet_funds
Definition: application.hpp:80
graphene::app::detail::create_example_genesis
graphene::chain::genesis_state_type create_example_genesis()
Definition: application.cpp:79
GRAPHENE_DEFAULT_MIN_WITNESS_COUNT
#define GRAPHENE_DEFAULT_MIN_WITNESS_COUNT
Definition: config.hpp:77
graphene::app::detail::application_impl::new_connection
void new_connection(const fc::http::websocket_connection_ptr &c)
Definition: application.cpp:188
graphene::app::application_options::api_limit_get_limit_orders_by_account
uint32_t api_limit_get_limit_orders_by_account
Definition: application.hpp:63
graphene::chain::genesis_state_type::initial_timestamp
time_point_sec initial_timestamp
Definition: genesis_state.hpp:103
graphene::egenesis::get_egenesis_json_hash
fc::sha256 get_egenesis_json_hash()
Definition: egenesis_none.cpp:43
graphene::app::detail::application_impl::get_current_block_interval_in_seconds
uint8_t get_current_block_interval_in_seconds() const override
Definition: application.cpp:1072
FC_THROW
#define FC_THROW( ...)
Definition: exception.hpp:366
graphene::app::application_options::api_limit_get_withdraw_permissions_by_giver
uint32_t api_limit_get_withdraw_permissions_by_giver
Definition: application.hpp:76
FC_LOG_AND_RETHROW
#define FC_LOG_AND_RETHROW()
Definition: exception.hpp:395
graphene::app::application::enable_plugin
void enable_plugin(const string &name) const
Definition: application.cpp:1429
GRAPHENE_NET_MAX_NESTED_OBJECTS
#define GRAPHENE_NET_MAX_NESTED_OBJECTS
Definition: config.hpp:112
graphene::net::message
Definition: message.hpp:58
fc::ip::endpoint::from_string
static endpoint from_string(const string &s)
Definition: ip.cpp:81
graphene::app::application_options::api_limit_lookup_committee_member_accounts
uint32_t api_limit_lookup_committee_member_accounts
Definition: application.hpp:72
graphene::chain::genesis_state_type::initial_chain_id
chain_id_type initial_chain_id
Definition: genesis_state.hpp:119
fee_schedule.hpp
api_access.hpp
egenesis.hpp
fc::json::from_string
static variant from_string(const string &utf8_str, parse_type ptype=legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition: json.cpp:458
fc::sha256
Definition: sha256.hpp:10
graphene::app::detail::application_impl::get_head_block_id
graphene::net::item_hash_t get_head_block_id() const override
Definition: application.cpp:1057
fc::http::websocket_connection_ptr
std::shared_ptr< websocket_connection > websocket_connection_ptr
Definition: websocket.hpp:47
plugin.hpp
graphene::net::node_ptr
std::shared_ptr< node > node_ptr
Definition: node.hpp:326
api_connection.hpp
graphene::app::detail::application_impl::add_available_plugin
void add_available_plugin(std::shared_ptr< abstract_plugin > p)
Add an available plugin.
Definition: application.cpp:1147
graphene::app::application_options::api_limit_get_relative_account_history
uint32_t api_limit_get_relative_account_history
Definition: application.hpp:49
graphene::egenesis::compute_egenesis_json
void compute_egenesis_json(std::string &result)
Definition: egenesis_none.cpp:38
graphene::app::application::chain_database
std::shared_ptr< chain::database > chain_database() const
Definition: application.cpp:1404
graphene::net::item_hash_t
fc::ripemd160 item_hash_t
Definition: core_messages.hpp:48
graphene::app::application_options::api_limit_get_account_history_operations
uint32_t api_limit_get_account_history_operations
Definition: application.hpp:47
graphene::app::application_options::api_limit_get_account_history_by_operations
uint32_t api_limit_get_account_history_by_operations
Definition: application.hpp:48
GRAPHENE_CURRENT_DB_VERSION
const std::string GRAPHENE_CURRENT_DB_VERSION
Definition: config.hpp:35
graphene::app::application_options::api_limit_list_htlcs
uint32_t api_limit_list_htlcs
Definition: application.hpp:74
GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION
#define GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION(type)
Definition: types.hpp:86
graphene::chain::genesis_state_type::initial_accounts
vector< initial_account_type > initial_accounts
Definition: genesis_state.hpp:107
graphene::app::detail::application_impl::handle_message
void handle_message(const graphene::net::message &message_to_process) override
Called when a new message comes in from the network other than a block or a transaction....
Definition: application.cpp:749
GRAPHENE_SYMBOL
#define GRAPHENE_SYMBOL
Definition: config.hpp:26
graphene::app::detail::application_impl::~application_impl
virtual ~application_impl()
Definition: application.cpp:117
fc::seconds
microseconds seconds(int64_t s)
Definition: time.hpp:34
core_messages.hpp
graphene::app::application_options::get_default
static constexpr application_options get_default()
Definition: application.hpp:84
graphene::app::application_options::api_limit_get_full_accounts_subscribe
uint32_t api_limit_get_full_accounts_subscribe
Definition: application.hpp:60
graphene::app::detail::application_impl::get_chain_id
graphene::chain::chain_id_type get_chain_id() const override
Definition: application.cpp:838
graphene::protocol::block_header::witness
witness_id_type witness
Definition: block.hpp:36
graphene::protocol::block_header::block_num
uint32_t block_num() const
Definition: block.hpp:34
fc::ip::endpoint
Definition: ip.hpp:65
graphene::app::application::initialize
void initialize(const fc::path &data_dir, std::shared_ptr< boost::program_options::variables_map > options) const
Definition: application.cpp:1354
graphene::app::application_options::api_limit_get_htlc_by
uint32_t api_limit_get_htlc_by
Definition: application.hpp:75
logger_config.hpp
graphene::app::application::~application
~application()
Definition: application.cpp:1167
graphene::app::application_options::api_limit_get_key_references
uint32_t api_limit_get_key_references
Definition: application.hpp:57
graphene::app::application_options::api_limit_get_account_history
uint32_t api_limit_get_account_history
Definition: application.hpp:46
graphene::app::detail::application_impl::has_item
bool has_item(const net::item_id &id) override
Definition: application.cpp:640
graphene::net::item_id
Definition: core_messages.hpp:49
graphene::app::application::get_api_access_info
fc::optional< api_access_info > get_api_access_info(const string &username) const
Definition: application.cpp:1414
graphene::app::detail::application_impl::set_api_access_info
void set_api_access_info(const string &username, api_access_info &&permissions)
Definition: application.cpp:627
asio.hpp
graphene::app::detail::application_impl::set_api_limit
void set_api_limit()
Definition: application.cpp:328
graphene::app::detail::application_impl::enable_plugin
void enable_plugin(const string &name)
Enables a plugin.
Definition: application.cpp:1111
types.hpp
graphene::app::detail::application_impl::reset_websocket_server
void reset_websocket_server()
Definition: application.cpp:222
fc::path
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
ilog
#define ilog(FORMAT,...)
Definition: logger.hpp:117
file_appender.hpp
edump
#define edump(SEQ)
Definition: logger.hpp:182
dlog
#define dlog(FORMAT,...)
Definition: logger.hpp:100
graphene::app::api_access
Definition: api_access.hpp:48
graphene::app::detail::application_impl::reset_p2p_node
void reset_p2p_node(const fc::path &data_dir)
Definition: application.cpp:122
graphene::app::application_options::api_limit_get_call_orders
uint32_t api_limit_get_call_orders
Definition: application.hpp:67
graphene::app::application::get_plugin
std::shared_ptr< abstract_plugin > get_plugin(const string &name) const
Definition: application.cpp:1389
fc::time_point_sec
Definition: time.hpp:74
graphene::app::application_options::api_limit_get_full_accounts
uint32_t api_limit_get_full_accounts
Definition: application.hpp:58
graphene::protocol::signed_block::transactions
vector< processed_transaction > transactions
Definition: block.hpp:68
fc::variant::as
T as(uint32_t max_depth) const
Definition: variant.hpp:337
graphene::app::detail::application_impl::startup
void startup()
Definition: application.cpp:597
graphene::app::application::syncing_finished
boost::signals2::signal< void()> syncing_finished
Emitted when syncing finishes (is_finished_syncing will return true)
Definition: application.hpp:150
graphene::app::detail::application_impl::sync_status
void sync_status(uint32_t item_type, uint32_t item_count) override
Definition: application.cpp:1028
graphene::protocol::block_id_type
fc::ripemd160 block_id_type
Definition: types.hpp:304
graphene::app::detail::application_impl::estimate_last_known_fork_from_git_revision_timestamp
uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override
Definition: application.cpp:1062
graphene::app::application_options::api_limit_get_liquidity_pools
uint32_t api_limit_get_liquidity_pools
Definition: application.hpp:79
fc::exception::to_detail_string
std::string to_detail_string(log_level ll=log_level::all) const
Definition: exception.cpp:183
graphene::app::application_options::api_limit_get_account_limit_orders
uint32_t api_limit_get_account_limit_orders
Definition: application.hpp:64
graphene::app::detail::application_impl::_force_validate
bool _force_validate
Definition: application_impl.hxx:20
graphene::app::application_options::api_limit_get_liquidity_pool_history
uint32_t api_limit_get_liquidity_pool_history
Definition: application.hpp:53
graphene::protocol::block_header::timestamp
fc::time_point_sec timestamp
Definition: block.hpp:35
exceptions.hpp
graphene::app::application_options::api_limit_get_withdraw_permissions_by_recipient
uint32_t api_limit_get_withdraw_permissions_by_recipient
Definition: application.hpp:77
graphene::app::application_options::api_limit_get_full_accounts_lists
uint32_t api_limit_get_full_accounts_lists
Definition: application.hpp:59
graphene::app::detail::application_impl::get_item
graphene::net::message get_item(const graphene::net::item_id &id) override
Definition: application.cpp:822
graphene::app::application_options::api_limit_get_limit_orders
uint32_t api_limit_get_limit_orders
Definition: application.hpp:62
graphene::app::application_options::api_limit_get_storage_info
uint32_t api_limit_get_storage_info
Definition: application.hpp:82
graphene::app::detail::application_impl::_is_block_producer
bool _is_block_producer
Definition: application_impl.hxx:19
graphene::app::detail::application_impl::get_block_ids
std::vector< graphene::net::item_hash_t > get_block_ids(const std::vector< graphene::net::item_hash_t > &blockchain_synopsis, uint32_t &remaining_item_count, uint32_t limit) override
Definition: application.cpp:771
graphene::app::application_options::api_limit_get_credit_offers
uint32_t api_limit_get_credit_offers
Definition: application.hpp:81
application_impl.hxx
graphene::app::api_access_info::allowed_apis
boost::container::flat_set< std::string > allowed_apis
Definition: api_access.hpp:45
graphene::app::application::set_program_options
void set_program_options(boost::program_options::options_description &command_line_options, boost::program_options::options_description &configuration_file_options) const
Definition: application.cpp:1173
graphene::app::application_options::api_limit_get_settle_orders
uint32_t api_limit_get_settle_orders
Definition: application.hpp:68
graphene::app::detail::application_impl::get_api_access_info
fc::optional< api_access_info > get_api_access_info(const string &username) const
Definition: application.cpp:614
graphene::app::detail::application_impl::is_plugin_enabled
bool is_plugin_enabled(const string &name) const
Returns whether a plugin is enabled.
Definition: application.cpp:632
fc::time_point::now
static time_point now()
Definition: time.cpp:13
graphene::app::application::set_block_production
void set_block_production(bool producing_blocks)
Definition: application.cpp:1409
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
application.hpp
graphene::app::application::is_plugin_enabled
bool is_plugin_enabled(const string &name) const
Definition: application.cpp:1394
graphene::net::block_message::block
signed_block block
Definition: core_messages.hpp:112
db_with.hpp
graphene::protocol::processed_transaction
captures the result of evaluating the operations contained in the transaction
Definition: transaction.hpp:292
graphene::protocol::block_header::num_from_id
static uint32_t num_from_id(const block_id_type &id)
Definition: block.cpp:36
graphene::app::application_options::api_limit_get_assets
uint32_t api_limit_get_assets
Definition: application.hpp:55
graphene::app::detail::application_impl::initialize
void initialize(const fc::path &data_dir, std::shared_ptr< boost::program_options::variables_map > options)
Definition: application.cpp:264
graphene::chain::database::skip_witness_schedule_check
@ skip_witness_schedule_check
used while reindexing
Definition: database.hpp:89
graphene::chain::genesis_state_type::initial_balances
vector< initial_balance_type > initial_balances
Definition: genesis_state.hpp:109
graphene::app::application_options::api_limit_get_trade_history_by_sequence
uint32_t api_limit_get_trade_history_by_sequence
Definition: application.hpp:52
graphene::app::api_access::permission_map
std::map< std::string, api_access_info > permission_map
Definition: api_access.hpp:50
graphene::app::application::is_finished_syncing
bool is_finished_syncing() const
Definition: application.cpp:1424
fc::time_point_sec::min
static time_point_sec min()
Definition: time.hpp:87
graphene::chain::genesis_state_type
Definition: genesis_state.hpp:40
base64.hpp
fc::time_point
Definition: time.hpp:44
graphene::chain::genesis_state_type::initial_parameters
chain_parameters initial_parameters
Definition: genesis_state.hpp:105
graphene::app::application_options::has_market_history_plugin
bool has_market_history_plugin
Definition: application.hpp:44
fc::read_file_contents
void read_file_contents(const fc::path &filename, std::string &result)
Definition: fstream.cpp:107
graphene::app::detail::application_impl::_app_options
application_options _app_options
Definition: application_impl.hxx:21
std
Definition: zeroed_array.hpp:76
graphene::app::application::startup
void startup()
Definition: application.cpp:1362
graphene::app::application::application
application()
Definition: application.cpp:1161
graphene::chain::database::skip_block_size_check
@ skip_block_size_check
used when applying locally generated transactions
Definition: database.hpp:83
graphene::chain::genesis_state_type::initial_active_witnesses
uint64_t initial_active_witnesses
Definition: genesis_state.hpp:111
logger.hpp
graphene::app::detail::application_impl::get_block_number
uint32_t get_block_number(const graphene::net::item_hash_t &block_id) override
Definition: application.cpp:1041
fstream.hpp
graphene::chain::database::skip_merkle_check
@ skip_merkle_check
used while reindexing
Definition: database.hpp:86
graphene::protocol::chain_parameters::get_mutable_fees
fee_schedule & get_mutable_fees()
Definition: chain_parameters.hpp:51
fc::serial_valve::do_serial
auto do_serial(const Functor1 &f1, const Functor2 &f2) -> decltype(f2())
Definition: parallel.hpp:81
graphene::app::detail::application_impl::get_block_time
fc::time_point_sec get_block_time(const graphene::net::item_hash_t &block_id) override
Definition: application.cpp:1050
graphene::app::application_options::api_limit_get_market_history
uint32_t api_limit_get_market_history
Definition: application.hpp:50
graphene::net::trx_message
Definition: core_messages.hpp:93
graphene::app::application_options::api_limit_get_top_markets
uint32_t api_limit_get_top_markets
Definition: application.hpp:54
fc::create_directories
void create_directories(const path &p)
Definition: filesystem.cpp:210
graphene::app::detail::application_impl::connection_count_changed
void connection_count_changed(uint32_t c) override
Definition: application.cpp:1036
graphene::protocol::signed_block_header::id
const block_id_type & id() const
Definition: block.cpp:41
fc::asio::default_io_service_scope::set_num_threads
static void set_num_threads(uint16_t num_threads)
Definition: asio.cpp:140
graphene::app::detail::application_impl::reset_websocket_tls_server
void reset_websocket_tls_server()
Definition: application.cpp:239
graphene::app::detail::application_impl::handle_block
bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode, std::vector< graphene::net::message_hash_type > &contained_transaction_msg_ids) override
allows the application to validate an item prior to broadcasting to peers.
Definition: application.cpp:660
graphene::app::application::get_options
const application_options & get_options() const
Definition: application.cpp:1439
fc::optional
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
graphene::app::application_options::api_limit_get_top_voters
uint32_t api_limit_get_top_voters
Definition: application.hpp:61
graphene::chain::database::skip_witness_signature
@ skip_witness_signature
used while reindexing
Definition: database.hpp:80
graphene::app::api_access_info
Definition: api_access.hpp:36
key_conversion.hpp
fc::ip::endpoint::port
uint16_t port() const
Definition: ip.cpp:78
graphene::app::application_options::api_limit_get_grouped_limit_orders
uint32_t api_limit_get_grouped_limit_orders
Definition: application.hpp:65
fc::json::from_file
static variant from_file(const fc::path &p, parse_type ptype=legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition: json.cpp:767
FC_THROW_EXCEPTION
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:379
graphene::app::application_options::api_limit_lookup_witness_accounts
uint32_t api_limit_lookup_witness_accounts
Definition: application.hpp:71
graphene::app::application_options::api_limit_get_trade_history
uint32_t api_limit_get_trade_history
Definition: application.hpp:51
graphene::chain::database::skip_transaction_dupe_check
@ skip_transaction_dupe_check
used while reindexing
Definition: database.hpp:82
GRAPHENE_ASSERT
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
Definition: exceptions.hpp:28
api.hpp
graphene::app::application_options::api_limit_lookup_accounts
uint32_t api_limit_lookup_accounts
Definition: application.hpp:70
graphene::app::application_options::api_limit_get_order_book
uint32_t api_limit_get_order_book
Definition: application.hpp:66
graphene::app::detail::application_impl::get_blockchain_synopsis
std::vector< graphene::net::item_hash_t > get_blockchain_synopsis(const graphene::net::item_hash_t &reference_point, uint32_t number_of_blocks_after_reference_point) override
Definition: application.cpp:901
fc::ecc::private_key::regenerate
static private_key regenerate(const fc::sha256 &secret)
Definition: elliptic_impl_priv.cpp:52
graphene::protocol::fee_schedule::get_default
static const fee_schedule & get_default()
Definition: fee_schedule.cpp:42
fc::api< graphene::app::login_api >
graphene::app::detail::application_impl::is_included_block
bool is_included_block(const graphene::chain::block_id_type &block_id)
Definition: application.cpp:755
graphene::chain::vesting_balance_type::witness
@ witness
fc::sha256::hash
static sha256 hash(const char *d, uint32_t dlen)
Definition: sha256.cpp:41
graphene
Definition: api.cpp:48
fc::base64_decode
std::string base64_decode(const std::string &encoded_string)
Definition: base64.cpp:96
fc::exists
bool exists(const path &p)
Definition: filesystem.cpp:209
graphene::protocol::address
a 160 bit hash of a public key
Definition: address.hpp:44
graphene::chain::database::skip_nothing
@ skip_nothing
Definition: database.hpp:79
graphene::app::application_options
Definition: application.hpp:38
graphene::app::application_options::enable_subscribe_to_all
bool enable_subscribe_to_all
Definition: application.hpp:41
graphene::app::application_options::has_api_helper_indexes_plugin
bool has_api_helper_indexes_plugin
Definition: application.hpp:43
graphene::app::application::p2p_node
net::node_ptr p2p_node()
Definition: application.cpp:1399
graphene::protocol::chain_parameters::block_interval
uint8_t block_interval
interval in seconds between blocks
Definition: chain_parameters.hpp:53
graphene::net::trx_message::trx
graphene::protocol::precomputable_transaction trx
Definition: core_messages.hpp:97
elog
#define elog(FORMAT,...)
Definition: logger.hpp:129