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" );
278 _force_validate =
true;
281 if ( _options->count(
"enable-subscribe-to-all") > 0 )
282 _app_options.enable_subscribe_to_all = _options->at(
"enable-subscribe-to-all" ).as<
bool>();
286 if( is_plugin_enabled(
"market_history" ) )
287 _app_options.has_market_history_plugin =
true;
289 ilog(
"Market history plugin is not enabled");
291 if( is_plugin_enabled(
"api_helper_indexes" ) )
292 _app_options.has_api_helper_indexes_plugin =
true;
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" );
322 _apiaccess.permission_map[
"*"] = wild_access;
325 initialize_plugins();
329 if (_options->count(
"api-limit-get-account-history-operations") > 0) {
330 _app_options.api_limit_get_account_history_operations =
331 _options->at(
"api-limit-get-account-history-operations").as<uint32_t>();
333 if(_options->count(
"api-limit-get-account-history") > 0){
334 _app_options.api_limit_get_account_history =
335 _options->at(
"api-limit-get-account-history").as<uint32_t>();
337 if(_options->count(
"api-limit-get-grouped-limit-orders") > 0){
338 _app_options.api_limit_get_grouped_limit_orders =
339 _options->at(
"api-limit-get-grouped-limit-orders").as<uint32_t>();
341 if(_options->count(
"api-limit-get-market-history") > 0){
342 _app_options.api_limit_get_market_history =
343 _options->at(
"api-limit-get-market-history").as<uint32_t>();
345 if(_options->count(
"api-limit-get-relative-account-history") > 0){
346 _app_options.api_limit_get_relative_account_history =
347 _options->at(
"api-limit-get-relative-account-history").as<uint32_t>();
349 if(_options->count(
"api-limit-get-account-history-by-operations") > 0){
350 _app_options.api_limit_get_account_history_by_operations =
351 _options->at(
"api-limit-get-account-history-by-operations").as<uint32_t>();
353 if(_options->count(
"api-limit-get-asset-holders") > 0){
354 _app_options.api_limit_get_asset_holders =
355 _options->at(
"api-limit-get-asset-holders").as<uint32_t>();
357 if(_options->count(
"api-limit-get-key-references") > 0){
358 _app_options.api_limit_get_key_references =
359 _options->at(
"api-limit-get-key-references").as<uint32_t>();
361 if(_options->count(
"api-limit-get-htlc-by") > 0) {
362 _app_options.api_limit_get_htlc_by =
363 _options->at(
"api-limit-get-htlc-by").as<uint32_t>();
365 if(_options->count(
"api-limit-get-full-accounts") > 0) {
366 _app_options.api_limit_get_full_accounts =
367 _options->at(
"api-limit-get-full-accounts").as<uint32_t>();
369 if(_options->count(
"api-limit-get-full-accounts-lists") > 0) {
370 _app_options.api_limit_get_full_accounts_lists =
371 _options->at(
"api-limit-get-full-accounts-lists").as<uint32_t>();
373 if(_options->count(
"api-limit-get-full-accounts-subscribe") > 0) {
374 _app_options.api_limit_get_full_accounts_subscribe =
375 _options->at(
"api-limit-get-full-accounts-subscribe").as<uint32_t>();
377 if(_options->count(
"api-limit-get-top-voters") > 0) {
378 _app_options.api_limit_get_top_voters =
379 _options->at(
"api-limit-get-top-voters").as<uint32_t>();
381 if(_options->count(
"api-limit-get-call-orders") > 0) {
382 _app_options.api_limit_get_call_orders =
383 _options->at(
"api-limit-get-call-orders").as<uint32_t>();
385 if(_options->count(
"api-limit-get-settle-orders") > 0) {
386 _app_options.api_limit_get_settle_orders =
387 _options->at(
"api-limit-get-settle-orders").as<uint32_t>();
389 if(_options->count(
"api-limit-get-assets") > 0) {
390 _app_options.api_limit_get_assets =
391 _options->at(
"api-limit-get-assets").as<uint32_t>();
393 if(_options->count(
"api-limit-get-limit-orders") > 0){
394 _app_options.api_limit_get_limit_orders =
395 _options->at(
"api-limit-get-limit-orders").as<uint32_t>();
397 if(_options->count(
"api-limit-get-limit-orders-by-account") > 0){
398 _app_options.api_limit_get_limit_orders_by_account =
399 _options->at(
"api-limit-get-limit-orders-by-account").as<uint32_t>();
401 if(_options->count(
"api-limit-get-order-book") > 0){
402 _app_options.api_limit_get_order_book =
403 _options->at(
"api-limit-get-order-book").as<uint32_t>();
405 if(_options->count(
"api-limit-list-htlcs") > 0){
406 _app_options.api_limit_list_htlcs =
407 _options->at(
"api-limit-list-htlcs").as<uint32_t>();
409 if(_options->count(
"api-limit-lookup-accounts") > 0) {
410 _app_options.api_limit_lookup_accounts =
411 _options->at(
"api-limit-lookup-accounts").as<uint32_t>();
413 if(_options->count(
"api-limit-lookup-witness-accounts") > 0) {
414 _app_options.api_limit_lookup_witness_accounts =
415 _options->at(
"api-limit-lookup-witness-accounts").as<uint32_t>();
417 if(_options->count(
"api-limit-lookup-committee-member-accounts") > 0) {
418 _app_options.api_limit_lookup_committee_member_accounts =
419 _options->at(
"api-limit-lookup-committee-member-accounts").as<uint32_t>();
421 if(_options->count(
"api-limit-lookup-vote-ids") > 0) {
422 _app_options.api_limit_lookup_vote_ids =
423 _options->at(
"api-limit-lookup-vote-ids").as<uint32_t>();
425 if(_options->count(
"api-limit-get-account-limit-orders") > 0) {
426 _app_options.api_limit_get_account_limit_orders =
427 _options->at(
"api-limit-get-account-limit-orders").as<uint32_t>();
429 if(_options->count(
"api-limit-get-collateral-bids") > 0) {
430 _app_options.api_limit_get_collateral_bids =
431 _options->at(
"api-limit-get-collateral-bids").as<uint32_t>();
433 if(_options->count(
"api-limit-get-top-markets") > 0) {
434 _app_options.api_limit_get_top_markets =
435 _options->at(
"api-limit-get-top-markets").as<uint32_t>();
437 if(_options->count(
"api-limit-get-trade-history") > 0) {
438 _app_options.api_limit_get_trade_history =
439 _options->at(
"api-limit-get-trade-history").as<uint32_t>();
441 if(_options->count(
"api-limit-get-trade-history-by-sequence") > 0) {
442 _app_options.api_limit_get_trade_history_by_sequence =
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) {
446 _app_options.api_limit_get_withdraw_permissions_by_giver =
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) {
450 _app_options.api_limit_get_withdraw_permissions_by_recipient =
451 _options->at(
"api-limit-get-withdraw-permissions-by-recipient").as<uint32_t>();
453 if(_options->count(
"api-limit-get-tickets") > 0) {
454 _app_options.api_limit_get_tickets =
455 _options->at(
"api-limit-get-tickets").as<uint32_t>();
457 if(_options->count(
"api-limit-get-liquidity-pools") > 0) {
458 _app_options.api_limit_get_liquidity_pools =
459 _options->at(
"api-limit-get-liquidity-pools").as<uint32_t>();
461 if(_options->count(
"api-limit-get-liquidity-pool-history") > 0) {
462 _app_options.api_limit_get_liquidity_pool_history =
463 _options->at(
"api-limit-get-liquidity-pool-history").as<uint32_t>();
465 if(_options->count(
"api-limit-get-samet-funds") > 0) {
466 _app_options.api_limit_get_samet_funds =
467 _options->at(
"api-limit-get-samet-funds").as<uint32_t>();
469 if(_options->count(
"api-limit-get-credit-offers") > 0) {
470 _app_options.api_limit_get_credit_offers =
471 _options->at(
"api-limit-get-credit-offers").as<uint32_t>();
473 if(_options->count(
"api-limit-get-storage-info") > 0) {
474 _app_options.api_limit_get_storage_info =
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() )
608 reset_p2p_node(_data_dir);
610 reset_websocket_server();
611 reset_websocket_tls_server();
617 auto it = _apiaccess.permission_map.find(username);
618 if( it == _apiaccess.permission_map.end() )
620 it = _apiaccess.permission_map.find(
"*");
621 if( it == _apiaccess.permission_map.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", );
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] () {
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;
729 _self.syncing_finished();
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;
916 if (is_included_block(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;
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;
1154 _is_block_producer = producing_blocks;
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;
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
const application_options & get_options() const
fc::optional< api_access_info > get_api_access_info(const string &username) const
void enable_plugin(const string &name)
Enables a plugin.
const std::string GRAPHENE_CURRENT_DB_VERSION
void add_available_plugin(std::shared_ptr< abstract_plugin > p)
Add an available plugin.
bool exists(const path &p)
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.
chain_id_type initial_chain_id
void enable_plugin(const string &name) const
fc::optional< api_access_info > get_api_access_info(const string &username) const
#define GRAPHENE_DEFAULT_MIN_WITNESS_COUNT
std::shared_ptr< chain::database > chain_database() const
bool has_item(const net::item_id &id) override
bool is_plugin_enabled(const string &name) const
graphene::chain::genesis_state_type create_example_genesis()
void set_program_options(boost::program_options::options_description &command_line_options, boost::program_options::options_description &configuration_file_options) const
void set_block_production(bool producing_blocks)
#define GRAPHENE_NET_MAX_NESTED_OBJECTS
void initialize(const fc::path &data_dir, std::shared_ptr< boost::program_options::variables_map > options)
static constexpr application_options get_default()
void error_encountered(const std::string &message, const fc::oexception &error) override
bool is_included_block(const graphene::chain::block_id_type &block_id)
uint32_t get_block_number(const graphene::net::item_hash_t &block_id) override
bool is_finished_syncing() const
void initialize(const fc::path &data_dir, std::shared_ptr< boost::program_options::variables_map > options) const
void connection_count_changed(uint32_t c) override
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
std::shared_ptr< node > node_ptr
vector< initial_balance_type > initial_balances
void with_skip_flags(database &db, uint32_t skip_flags, Lambda callback)
void create_directories(const path &p)
void read_file_contents(const fc::path &filename, std::string &result)
vector< initial_witness_type > initial_witness_candidates
void reset_websocket_tls_server()
static variant from_file(const fc::path &p, parse_type ptype=legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
std::shared_ptr< websocket_connection > websocket_connection_ptr
std::shared_ptr< abstract_plugin > get_plugin(const string &name) const
fc::ripemd160 item_hash_t
fc::ripemd160 block_id_type
static sha256 hash(const char *d, uint32_t dlen)
provides stack-based nullable value similar to boost::optional
graphene::protocol::precomputable_transaction trx
std::string key_to_wif(const fc::sha256 &private_secret)
vector< initial_account_type > initial_accounts
static const fee_schedule & get_default()
void set_api_access_info(const string &username, api_access_info &&permissions)
chain_parameters initial_parameters
void set_block_production(bool producing_blocks)
microseconds seconds(int64_t s)
graphene::net::item_hash_t get_head_block_id() const override
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
T as(uint32_t max_depth) const
void handle_transaction(const graphene::net::trx_message &transaction_message) override
Called when a new transaction comes in from the network.
static private_key regenerate(const fc::sha256 &secret)
time_point_sec initial_timestamp
#define GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION(type)
uint8_t get_current_block_interval_in_seconds() const override
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
static endpoint from_string(const string &s)
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
void set_api_access_info(const string &username, api_access_info &&permissions)
fc::time_point_sec get_block_time(const graphene::net::item_hash_t &block_id) override
used while reindexing – note this skips expiration check too
vector< initial_committee_member_type > initial_committee_candidates
std::string to_detail_string(log_level ll=log_level::all) const
std::string to_string(double)
fc::sha256 get_egenesis_json_hash()
uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override
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. Currently there are no other possible messages, so this should never be called.
std::string base64_decode(const std::string &encoded_string)
static time_point_sec min()
static variant from_string(const string &utf8_str, parse_type ptype=legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
constexpr int64_t GRAPHENE_MAX_SHARE_SUPPLY(1000000000000000LL)
uint64_t initial_active_witnesses
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
a 160 bit hash of a public key
void sync_status(uint32_t item_type, uint32_t item_count) override
void new_connection(const fc::http::websocket_connection_ptr &c)
graphene::net::message get_item(const graphene::net::item_id &id) override
const string & get_node_info() const
wraps boost::filesystem::path to provide platform independent path manipulation.
#define FC_LOG_AND_RETHROW()
vector< processed_transaction > transactions
void reset_p2p_node(const fc::path &data_dir)
void compute_egenesis_json(std::string &result)
fee_schedule & get_mutable_fees()
captures the result of evaluating the operations contained in the transaction
virtual ~application_impl()
used by non-witness nodes
graphene::chain::chain_id_type get_chain_id() const override
uint8_t block_interval
interval in seconds between blocks
static void set_num_threads(uint16_t num_threads)
bool is_plugin_enabled(const string &name) const
Returns whether a plugin is enabled.
void reset_websocket_server()
used when applying locally generated transactions
boost::container::flat_set< std::string > allowed_apis