48 #include <boost/filesystem/path.hpp>
49 #include <boost/signals2.hpp>
50 #include <boost/range/algorithm/reverse.hpp>
51 #include <boost/algorithm/string.hpp>
59 #include <boost/range/adaptor/reversed.hpp>
65 using net::block_message;
66 using net::trx_message;
68 using chain::block_header;
69 using chain::signed_block_header;
70 using chain::signed_block;
75 namespace bpo = boost::program_options;
92 nathan_key.get_public_key(),
93 nathan_key.get_public_key(),
99 initial_state.
initial_accounts.emplace_back(
"nathan", nathan_key.get_public_key());
105 return initial_state;
115 namespace graphene {
namespace app {
namespace detail {
124 _p2p_network = std::make_shared<net::node>(
"BitShares Reference Implementation");
126 _p2p_network->load_configuration(data_dir /
"p2p");
127 _p2p_network->set_node_delegate(shared_from_this());
129 if( _options->count(
"seed-node") > 0 )
131 auto seeds = _options->at(
"seed-node").as<vector<string>>();
132 _p2p_network->add_seed_nodes(seeds);
135 if( _options->count(
"seed-nodes") > 0 )
137 auto seeds_str = _options->at(
"seed-nodes").as<
string>();
139 _p2p_network->add_seed_nodes(seeds);
143 vector<string> seeds = {
144 #include "../egenesis/seed-nodes.txt"
146 _p2p_network->add_seed_nodes(seeds);
149 if( _options->count(
"p2p-advertise-peer-algorithm" ) > 0 )
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 );
160 if( _options->count(
"p2p-endpoint") > 0 )
165 if( _options->count(
"p2p-inbound-endpoint") > 0 )
169 if ( _options->count(
"p2p-accept-incoming-connections") > 0 )
170 _p2p_network->set_accept_incoming_connections( _options->at(
"p2p-accept-incoming-connections").as<
bool>() );
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>() );
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) );
180 ilog(
"Configured p2p node to not listen for incoming connections" );
182 _p2p_network->connect_to_p2p_network();
184 _chain_db->head_block_id()),
185 std::vector<uint32_t>());
191 auto login = std::make_shared<graphene::app::login_api>( _self );
194 std::string auth = c->get_request_header(
"Authorization");
195 if( boost::starts_with(auth,
"Basic ") ) {
200 std::vector<std::string> parts;
201 boost::split( parts, user_pass, boost::is_any_of(
":") );
205 const string& username = parts[0];
206 const string& password = parts[1];
207 login->login(username, password);
210 login->login(
"",
"");
213 if( login->is_database_api_allowed() )
214 wsc->register_api(login->database());
216 wsc->register_api(login->dummy());
219 c->set_session_data( wsc );
224 if( 0 == _options->count(
"rpc-endpoint") )
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>();
231 _websocket_server = std::make_shared<fc::http::websocket_server>( proxy_forward_header );
234 ilog(
"Configured websocket rpc to listen on ${ip}", (
"ip",_options->at(
"rpc-endpoint").as<
string>()));
236 _websocket_server->start_accept();
241 if( 0 == _options->count(
"rpc-tls-endpoint") )
243 if( 0 == _options->count(
"server-pem") )
245 wlog(
"Please specify a server-pem to use rpc-tls-endpoint" );
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>();
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 );
259 ilog(
"Configured websocket TLS rpc to listen on ${ip}", (
"ip",_options->at(
"rpc-tls-endpoint").as<
string>()));
261 _websocket_tls_server->start_accept();
266 _data_dir = data_dir;
269 if ( _options->count(
"io-threads") > 0 )
271 const uint16_t num_threads = _options->at(
"io-threads").as<uint16_t>();
275 if( _options->count(
"force-validate") > 0 )
277 ilog(
"All transaction signatures will be validated" );
281 if ( _options->count(
"enable-subscribe-to-all") > 0 )
289 ilog(
"Market history plugin is not enabled");
294 ilog(
"API helper indexes plugin is not enabled");
296 if (_options->count(
"api-node-info") > 0)
297 _node_info = _options->at(
"api-node-info").as<
string>();
299 if( _options->count(
"api-access") > 0 )
302 fc::path api_access_file = _options->at(
"api-access").as<boost::filesystem::path>();
305 "Failed to load file from ${path}", (
"path", api_access_file) );
308 ilog(
"Using api access file from ${path}",
309 (
"path", api_access_file) );
318 wild_access.
allowed_apis.insert(
"network_broadcast_api" );
321 wild_access.
allowed_apis.insert(
"custom_operations_api" );
325 initialize_plugins();
329 if (_options->count(
"api-limit-get-account-history-operations") > 0) {
331 _options->at(
"api-limit-get-account-history-operations").as<uint32_t>();
333 if(_options->count(
"api-limit-get-account-history") > 0){
335 _options->at(
"api-limit-get-account-history").as<uint32_t>();
337 if(_options->count(
"api-limit-get-grouped-limit-orders") > 0){
339 _options->at(
"api-limit-get-grouped-limit-orders").as<uint32_t>();
341 if(_options->count(
"api-limit-get-market-history") > 0){
343 _options->at(
"api-limit-get-market-history").as<uint32_t>();
345 if(_options->count(
"api-limit-get-relative-account-history") > 0){
347 _options->at(
"api-limit-get-relative-account-history").as<uint32_t>();
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>();
353 if(_options->count(
"api-limit-get-asset-holders") > 0){
355 _options->at(
"api-limit-get-asset-holders").as<uint32_t>();
357 if(_options->count(
"api-limit-get-key-references") > 0){
359 _options->at(
"api-limit-get-key-references").as<uint32_t>();
361 if(_options->count(
"api-limit-get-htlc-by") > 0) {
363 _options->at(
"api-limit-get-htlc-by").as<uint32_t>();
365 if(_options->count(
"api-limit-get-full-accounts") > 0) {
367 _options->at(
"api-limit-get-full-accounts").as<uint32_t>();
369 if(_options->count(
"api-limit-get-full-accounts-lists") > 0) {
371 _options->at(
"api-limit-get-full-accounts-lists").as<uint32_t>();
373 if(_options->count(
"api-limit-get-full-accounts-subscribe") > 0) {
375 _options->at(
"api-limit-get-full-accounts-subscribe").as<uint32_t>();
377 if(_options->count(
"api-limit-get-top-voters") > 0) {
379 _options->at(
"api-limit-get-top-voters").as<uint32_t>();
381 if(_options->count(
"api-limit-get-call-orders") > 0) {
383 _options->at(
"api-limit-get-call-orders").as<uint32_t>();
385 if(_options->count(
"api-limit-get-settle-orders") > 0) {
387 _options->at(
"api-limit-get-settle-orders").as<uint32_t>();
389 if(_options->count(
"api-limit-get-assets") > 0) {
391 _options->at(
"api-limit-get-assets").as<uint32_t>();
393 if(_options->count(
"api-limit-get-limit-orders") > 0){
395 _options->at(
"api-limit-get-limit-orders").as<uint32_t>();
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>();
401 if(_options->count(
"api-limit-get-order-book") > 0){
403 _options->at(
"api-limit-get-order-book").as<uint32_t>();
405 if(_options->count(
"api-limit-list-htlcs") > 0){
407 _options->at(
"api-limit-list-htlcs").as<uint32_t>();
409 if(_options->count(
"api-limit-lookup-accounts") > 0) {
411 _options->at(
"api-limit-lookup-accounts").as<uint32_t>();
413 if(_options->count(
"api-limit-lookup-witness-accounts") > 0) {
415 _options->at(
"api-limit-lookup-witness-accounts").as<uint32_t>();
417 if(_options->count(
"api-limit-lookup-committee-member-accounts") > 0) {
419 _options->at(
"api-limit-lookup-committee-member-accounts").as<uint32_t>();
421 if(_options->count(
"api-limit-lookup-vote-ids") > 0) {
423 _options->at(
"api-limit-lookup-vote-ids").as<uint32_t>();
425 if(_options->count(
"api-limit-get-account-limit-orders") > 0) {
427 _options->at(
"api-limit-get-account-limit-orders").as<uint32_t>();
429 if(_options->count(
"api-limit-get-collateral-bids") > 0) {
431 _options->at(
"api-limit-get-collateral-bids").as<uint32_t>();
433 if(_options->count(
"api-limit-get-top-markets") > 0) {
435 _options->at(
"api-limit-get-top-markets").as<uint32_t>();
437 if(_options->count(
"api-limit-get-trade-history") > 0) {
439 _options->at(
"api-limit-get-trade-history").as<uint32_t>();
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>();
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>();
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>();
453 if(_options->count(
"api-limit-get-tickets") > 0) {
455 _options->at(
"api-limit-get-tickets").as<uint32_t>();
457 if(_options->count(
"api-limit-get-liquidity-pools") > 0) {
459 _options->at(
"api-limit-get-liquidity-pools").as<uint32_t>();
461 if(_options->count(
"api-limit-get-liquidity-pool-history") > 0) {
463 _options->at(
"api-limit-get-liquidity-pool-history").as<uint32_t>();
465 if(_options->count(
"api-limit-get-samet-funds") > 0) {
467 _options->at(
"api-limit-get-samet-funds").as<uint32_t>();
469 if(_options->count(
"api-limit-get-credit-offers") > 0) {
471 _options->at(
"api-limit-get-credit-offers").as<uint32_t>();
473 if(_options->count(
"api-limit-get-storage-info") > 0) {
475 _options->at(
"api-limit-get-storage-info").as<uint32_t>();
482 ilog(
"Initializing database...");
483 if( _options->count(
"genesis-json") > 0 )
485 std::string genesis_str;
488 bool modified_genesis =
false;
489 if( _options->count(
"genesis-timestamp") > 0 )
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;
499 "Used genesis timestamp: ${timestamp} (PLEASE RECORD THIS)",
500 (
"timestamp", genesis.initial_timestamp.to_iso_string())
503 if( _options->count(
"dbg-init-key") > 0 )
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));
511 if( modified_genesis )
513 wlog(
"WARNING: GENESIS WAS MODIFIED, YOUR CHAIN ID MAY BE DIFFERENT");
514 genesis_str +=
"BOGUS";
521 std::string egenesis_json;
532 void application_impl::open_chain_database()
const
536 if( _options->count(
"resync-blockchain") > 0 )
537 _chain_db->wipe(_data_dir /
"blockchain",
true);
539 flat_map<uint32_t,block_id_type> loaded_checkpoints;
540 if( _options->count(
"checkpoint") > 0 )
542 auto cps = _options->at(
"checkpoint").as<vector<string>>();
543 loaded_checkpoints.reserve( cps.size() );
547 loaded_checkpoints[item.first] = item.second;
550 _chain_db->add_checkpoints( loaded_checkpoints );
552 if( _options->count(
"enable-standby-votes-tracking") > 0 )
554 _chain_db->enable_standby_votes_tracking( _options->at(
"enable-standby-votes-tracking").as<
bool>() );
557 if( _options->count(
"replay-blockchain") > 0 || _options->count(
"revalidate-blockchain") > 0 )
558 _chain_db->wipe( _data_dir /
"blockchain",
false );
564 if( _options->count(
"revalidate-blockchain") > 0 )
566 if( !loaded_checkpoints.empty() )
567 wlog(
"Warning - revalidate will not validate before last checkpoint" );
568 if( _options->count(
"force-validate") > 0 )
582 auto genesis_loader = [
this](){
583 return initialize_genesis_state();
592 elog(
"Caught exception ${e} in open(), you might want to force a replay", (
"e", e.
to_detail_string()) );
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>();
603 open_chain_database();
607 if( enable_p2p_network && _active_plugins.find(
"delayed_node" ) == _active_plugins.end() )
629 _apiaccess.
permission_map.insert(std::make_pair(username, std::move(permissions)));
634 return !(_active_plugins.find(name) == _active_plugins.end());
645 return _chain_db->is_known_block(
id.item_hash);
647 return _chain_db->is_known_transaction(
id.item_hash);
661 std::vector<graphene::net::message_hash_type>& contained_transaction_msg_ids)
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})",
676 (
"l", (latency.count()/1000))
677 (
"w",witness_account.name)
681 graphene::net::block_timestamp_in_future_exception,
682 "Rejecting block with timestamp in the future", );
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] () {
694 return _chain_db->push_block( blk_msg.
block, skip );
705 contained_transaction_msg_ids.reserve( contained_transaction_msg_ids.size()
715 }
catch (
const graphene::chain::unlinkable_block_exception& e ) {
717 elog(
"Error when pushing block:\n${e}", (
"e", e.to_detail_string()));
719 "Error when pushing block:\n${e}",
720 (
"e", e.to_detail_string()) );
726 if( !_is_finished_syncing && !sync_mode )
728 _is_finished_syncing =
true;
736 static int trx_count = 0;
740 ilog(
"Got ${c} transactions from network", (
"c",trx_count) );
745 _chain_db->precompute_parallel( transaction_message.
trx ).wait();
746 _chain_db->push_transaction( transaction_message.
trx );
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;
772 uint32_t& remaining_item_count,
775 vector<block_id_type> result;
776 remaining_item_count = 0;
777 if( _chain_db->head_block_num() == 0 )
780 result.reserve(limit);
783 if (blockchain_synopsis.empty() ||
784 (blockchain_synopsis.size() == 1 && blockchain_synopsis[0] ==
block_id_type()))
794 bool found_a_block_in_synopsis =
false;
795 for (
const item_hash_t& block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis))
797 (_chain_db->is_known_block(block_id_in_synopsis) &&
is_included_block(block_id_in_synopsis)))
799 last_known_block_id = block_id_in_synopsis;
800 found_a_block_in_synopsis =
true;
803 if (!found_a_block_in_synopsis)
805 "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis" );
808 num <= _chain_db->head_block_num() && result.size() < limit;
811 result.push_back(_chain_db->get_block_id_for_num(num));
827 auto opt_block = _chain_db->fetch_block_by_id(
id.item_hash);
829 elog(
"Couldn't find block ${id} -- corresponding ID in our chain is ${id2}",
835 return trx_message( _chain_db->get_recent_transaction(
id.item_hash ) );
840 return _chain_db->get_chain_id();
902 uint32_t number_of_blocks_after_reference_point)
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;
920 assert(reference_point_block_num > 0);
921 high_block_num = reference_point_block_num;
922 non_fork_high_block_num = high_block_num;
924 if (reference_point_block_num < low_block_num)
936 low_block_num = reference_point_block_num;
944 fork_history = _chain_db->get_block_ids_on_fork(reference_point);
947 assert(fork_history.size() >= 2);
949 if( fork_history.front() != reference_point )
951 edump( (fork_history)(reference_point) );
952 assert(fork_history.front() == reference_point);
955 fork_history.pop_back();
956 boost::reverse(fork_history);
959 non_fork_high_block_num = 0;
963 high_block_num = non_fork_high_block_num + fork_history.size();
970 elog(
"Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}",
971 (
"hash", reference_point)(
"exception", e) );
974 if (non_fork_high_block_num < low_block_num)
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");
987 high_block_num = _chain_db->head_block_num();
988 non_fork_high_block_num = high_block_num;
989 if (high_block_num == 0)
993 if( low_block_num == 0)
1003 uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point;
1009 if (low_block_num <= non_fork_high_block_num)
1010 synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num));
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;
1015 while (low_block_num <= high_block_num);
1052 auto opt_block = _chain_db->fetch_block_by_id( block_id );
1053 if( opt_block.valid() )
return opt_block->timestamp;
1059 return _chain_db->head_block_id();
1074 FC_ASSERT( _chain_db,
"Chain database is not operational" );
1075 return _chain_db->get_global_properties().parameters.block_interval;
1078 void application_impl::shutdown()
1080 ilog(
"Shutting down application" );
1081 if( _websocket_tls_server )
1082 _websocket_tls_server.reset();
1083 if( _websocket_server )
1084 _websocket_server.reset();
1088 ilog(
"Shutting down plugins" );
1093 ilog(
"Disconnecting from P2P network" );
1095 _p2p_network->close();
1096 _p2p_network.reset();
1099 ilog(
"P2P network is disabled" );
1103 ilog(
"Closing chain database" );
1108 ilog(
"Chain database is not open" );
1113 FC_ASSERT(_available_plugins[name],
"Unknown plugin '" + name +
"'");
1114 _active_plugins[name] = _available_plugins[name];
1117 void application_impl::initialize_plugins()
const
1119 for(
const auto& entry : _active_plugins )
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() ) );
1127 void application_impl::startup_plugins()
const
1129 for(
const auto& entry : _active_plugins )
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() ) );
1137 void application_impl::shutdown_plugins()
const
1139 for(
const auto& entry : _active_plugins )
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() ) );
1149 _available_plugins[p->plugin_name()] = p;
1159 namespace graphene {
namespace app {
1162 : my(
std::make_shared<detail::application_impl>(*this))
1169 ilog(
"Application quitting");
1174 boost::program_options::options_description& configuration_file_options)
const
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")
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!)")
1350 command_line_options.add(_cli_options);
1351 configuration_file_options.add(_cfg_options);
1355 std::shared_ptr<boost::program_options::variables_map> options)
const
1357 ilog(
"Initializing application" );
1358 my->initialize( data_dir, options );
1359 ilog(
"Done initializing application" );
1365 ilog(
"Starting up application" );
1367 ilog(
"Done starting up application" );
1372 elog(
"unexpected exception" );
1380 my->set_api_limit();
1385 elog(
"unexpected exception" );
1391 return my->_active_plugins[name];
1396 return my->is_plugin_enabled(name);
1401 return my->_p2p_network;
1406 return my->_chain_db;
1411 my->set_block_production(producing_blocks);
1416 return my->get_api_access_info( username );
1421 my->set_api_access_info(username, std::move(permissions));
1426 return my->_is_finished_syncing;
1431 my->enable_plugin(name);
1434 void application::add_available_plugin(std::shared_ptr<graphene::app::abstract_plugin> p)
const
1436 my->add_available_plugin(p);
1441 return my->_app_options;
1446 return my->_node_info;