44 #include <scorum/egenesis/egenesis.hpp>
46 #include <fc/time.hpp>
48 #include <graphene/net/core_messages.hpp>
49 #include <graphene/net/exceptions.hpp>
51 #include <graphene/utilities/key_conversion.hpp>
52 #include <graphene/utilities/git_revision.hpp>
53 #include <fc/git_revision.hpp>
55 #include <fc/smart_ref_impl.hpp>
57 #include <fc/io/fstream.hpp>
58 #include <fc/rpc/api_connection.hpp>
59 #include <fc/rpc/websocket_api.hpp>
60 #include <fc/network/resolve.hpp>
61 #include <fc/string.hpp>
63 #include <boost/algorithm/string.hpp>
64 #include <boost/filesystem/path.hpp>
65 #include <boost/signals2.hpp>
66 #include <boost/range/algorithm/reverse.hpp>
72 #include <fc/log/file_appender.hpp>
73 #include <fc/log/logger.hpp>
74 #include <fc/log/logger_config.hpp>
76 #include <boost/range/adaptor/reversed.hpp>
83 using graphene::net::item_hash_t;
84 using graphene::net::item_id;
85 using graphene::net::message;
86 using graphene::net::block_message;
87 using graphene::net::trx_message;
89 using protocol::block_header;
90 using protocol::signed_block_header;
91 using protocol::signed_block;
94 namespace bpo = boost::program_options;
105 using plugins_type = std::map<std::string, std::shared_ptr<abstract_plugin>>;
119 _p2p_network = std::make_shared<graphene::net::node>(
"Graphene Reference Implementation");
126 auto seeds =
_options->at(
"seed-node").as<std::vector<std::string>>();
127 for (
const std::string& endpoint_string : seeds)
132 for (
const fc::ip::endpoint& endpoint : endpoints)
134 ilog(
"Adding seed node ${endpoint}", (
"endpoint", endpoint));
139 catch (
const fc::exception& e)
141 wlog(
"caught exception ${e} while adding seed node ${endpoint}",
142 (
"e", e.to_detail_string())(
"endpoint", endpoint_string));
147 if (
_options->count(
"p2p-endpoint"))
149 auto p2p_endpoint =
_options->at(
"p2p-endpoint").as<std::string>();
151 FC_ASSERT(endpoints.size(),
"p2p-endpoint ${hostname} did not resolve", (
"hostname", p2p_endpoint));
159 if (
_options->count(
"p2p-max-connections"))
161 fc::variant_object node_param = fc::variant_object(
162 "maximum_number_of_connections", fc::variant(
_options->at(
"p2p-max-connections").as<uint32_t>()));
164 ilog(
"Setting p2p max connections to ${n}", (
"n", node_param[
"maximum_number_of_connections"]));
168 ilog(
"Configured p2p node to listen on ${ip}", (
"ip",
_p2p_network->get_actual_listening_endpoint()));
173 idump((head_block_id));
175 graphene::net::item_id(graphene::net::core_message_type_enum::block_message_type, head_block_id),
176 std::vector<uint32_t>());
178 FC_CAPTURE_AND_RETHROW()
185 std::string::size_type colon_pos = endpoint_string.find(
':');
186 if (colon_pos == std::string::npos)
187 FC_THROW(
"Missing required port number in endpoint string \"${endpoint_string}\"",
188 (
"endpoint_string", endpoint_string));
189 std::string port_string = endpoint_string.substr(colon_pos + 1);
192 uint16_t port = boost::lexical_cast<uint16_t>(port_string);
194 std::string hostname = endpoint_string.substr(0, colon_pos);
195 std::vector<fc::ip::endpoint> endpoints = fc::resolve(hostname, port);
196 if (endpoints.empty())
197 FC_THROW_EXCEPTION(fc::unknown_host_exception,
"The host name can not be resolved: ${hostname}",
198 (
"hostname", hostname));
201 catch (
const boost::bad_lexical_cast&)
203 FC_THROW(
"Bad port: ${port}", (
"port", port_string));
206 FC_CAPTURE_AND_RETHROW((endpoint_string))
213 if (!
_options->count(
"rpc-endpoint"))
221 auto rpc_endpoint =
_options->at(
"rpc-endpoint").as<std::string>();
222 ilog(
"Configured websocket rpc to listen on ${ip}", (
"ip", rpc_endpoint));
224 FC_ASSERT(endpoints.size(),
"rpc-endpoint ${hostname} did not resolve", (
"hostname", rpc_endpoint));
228 FC_CAPTURE_AND_RETHROW()
235 if (!
_options->count(
"rpc-tls-endpoint"))
241 wlog(
"Please specify a server-pem to use rpc-tls-endpoint");
246 =
_options->count(
"server-pem-password") ?
_options->at(
"server-pem-password").as<std::string>() :
"";
248 _options->at(
"server-pem").as<std::string>(), password);
251 [
this](
const fc::http::websocket_connection_ptr& c) {
on_connection(c); });
252 auto rpc_tls_endpoint =
_options->at(
"rpc-tls-endpoint").as<std::string>();
253 ilog(
"Configured websocket TLS rpc to listen on ${ip}", (
"ip", rpc_tls_endpoint));
255 FC_ASSERT(endpoints.size(),
"rpc-tls-endpoint ${hostname} did not resolve", (
"hostname", rpc_tls_endpoint));
259 FC_CAPTURE_AND_RETHROW()
264 std::shared_ptr<api_session_data> session = std::make_shared<api_session_data>();
265 session->wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
273 elog(
"Couldn't create API ${name}", (
"name", name));
276 session->api_map[name] = api;
277 api->register_api(*session->wsc);
279 c->set_session_data(session);
305 std::string genesis_str;
307 if (
_options->count(
"genesis-json"))
309 fc::path genesis_json_filename =
_options->at(
"genesis-json").as<boost::filesystem::path>();
311 fc::read_file_contents(genesis_json_filename, genesis_str);
315 scorum::egenesis::compute_egenesis_json(genesis_str);
318 FC_ASSERT(!genesis_str.empty());
328 static const char* default_data_subdir =
"blockchain";
333 ilog(
"node chain ID: ${chain_id}", (
"chain_id", genesis_state.
initial_chain_id));
351 if (
_options->count(
"shared-file-dir"))
362 fc::path block_log_dir =
_data_dir / default_data_subdir;
366 ilog(
"Starting Scorum node in write mode.");
369 if (
_options->count(
"resync-blockchain"))
376 flat_map<uint32_t, block_id_type> loaded_checkpoints;
379 auto cps =
_options->at(
"checkpoint").as<std::vector<std::string>>();
380 loaded_checkpoints.reserve(cps.size());
383 auto item = fc::json::from_string(cp).as<std::pair<uint32_t, block_id_type>>();
384 loaded_checkpoints[item.first] = item.second;
387 _chain_db->add_checkpoints(loaded_checkpoints);
389 if (
_options->count(
"replay-blockchain") && !
_options->count(
"resync-blockchain"))
391 ilog(
"Replaying blockchain on user request.");
393 uint32_t skip_flags =
_chain_db->get_reindex_skip_flags();
394 if (!
_options->at(
"replay-skip-witness-schedule-check").as<
bool>())
395 skip_flags &= ~
database::skip_witness_schedule_check;
405 if (
_options->count(
"force-validate"))
407 ilog(
"All transaction signatures will be validated");
413 ilog(
"Starting Scorum node in read mode.");
417 if (
_options->count(
"read-forward-rpc"))
423 catch (fc::exception& e)
425 wlog(
"Error connecting to remote RPC, network api forwarding disabled. ${e}",
426 (
"e", e.to_detail_string()));
434 for (
const std::string& api_access_str :
_options->at(
"api-user").as<std::vector<std::string>>())
453 wild_access.
allowed_apis.push_back(
"network_broadcast_api");
462 for (
const std::string& arg :
_options->at(
"public-api").as<std::vector<std::string>>())
464 std::vector<std::string> names;
465 boost::split(names, arg, boost::is_any_of(
" \t,"));
466 for (
const std::string& name : names)
468 ilog(
"API ${name} enabled publicly", (
"name", name));
487 optional<api_access_info>
result;
515 wlog(
"unknown api: ${api}", (
"api", ctx.
api_name));
518 return it->second(ctx);
524 virtual bool has_item(
const graphene::net::item_id&
id)
override
535 if (
id.item_type == graphene::net::block_message_type)
537 return _chain_db->is_known_block(
id.item_hash);
541 return _chain_db->is_known_transaction(
id.item_hash);
545 FC_CAPTURE_AND_RETHROW((
id))
558 std::vector<fc::uint160_t>& contained_transaction_message_ids)
override
564 uint32_t head_block_num;
569 fc_ilog(fc::logger::get(
"sync"),
570 "chain pushing sync block #${block_num} ${block_hash}, head is ${head}",
571 (
"block_num", blk_msg.block.block_num())(
"block_hash", blk_msg.block_id)(
"head",
574 fc_ilog(fc::logger::get(
"sync"),
"chain pushing block #${block_num} ${block_hash}, head is ${head}",
575 (
"block_num", blk_msg.block.block_num())(
"block_hash", blk_msg.block_id)(
"head",
578 if (sync_mode && blk_msg.block.block_num() % 10000 == 0)
580 ilog(
"Syncing Blockchain --- Got block: #${n} time: ${t}",
581 (
"t", blk_msg.block.timestamp)(
"n", blk_msg.block.block_num()));
584 time_point_sec now = fc::time_point::now();
586 uint64_t max_accept_time = now.sec_since_epoch();
588 FC_ASSERT(blk_msg.block.timestamp.sec_since_epoch() <= max_accept_time);
607 fc::microseconds latency = fc::time_point::now() - blk_msg.block.timestamp;
608 ilog(
"Got ${t} transactions on block ${b} by ${w} -- latency: ${l} ms",
609 (
"t", blk_msg.block.transactions.size())(
"b", blk_msg.block.block_num())(
610 "w", blk_msg.block.witness)(
"l", latency.count() / 1000));
615 catch (
const scorum::chain::unlinkable_block_exception& e)
618 fc_elog(fc::logger::get(
"sync"),
"Error when pushing block, current head block is ${head3}:\n${e}",
619 (
"e", e.to_detail_string())(
"head", head_block_num));
620 elog(
"Error when pushing block:\n${e}", (
"e", e.to_detail_string()));
621 FC_THROW_EXCEPTION(graphene::net::unlinkable_block_exception,
"Error when pushing block:\n${e}",
622 (
"e", e.to_detail_string()));
624 catch (
const fc::exception& e)
626 fc_elog(fc::logger::get(
"sync"),
"Error when pushing block, current head block is ${head}:\n${e}",
627 (
"e", e.to_detail_string())(
"head", head_block_num));
628 elog(
"Error when pushing block:\n${e}", (
"e", e.to_detail_string()));
634 FC_CAPTURE_AND_RETHROW((blk_msg)(sync_mode))
643 _chain_db->push_transaction(transaction_message.trx);
646 FC_CAPTURE_AND_RETHROW((transaction_message))
652 FC_THROW(
"Invalid Message Type");
660 return block_id == block_id_in_preferred_chain;
673 virtual std::vector<item_hash_t>
get_block_ids(
const std::vector<item_hash_t>& blockchain_synopsis,
674 uint32_t& remaining_item_count,
675 uint32_t limit)
override
680 std::vector<block_id_type>
result;
681 remaining_item_count = 0;
690 if (blockchain_synopsis.empty()
691 || (blockchain_synopsis.size() == 1 && blockchain_synopsis[0] ==
block_id_type()))
700 bool found_a_block_in_synopsis =
false;
702 for (
const item_hash_t& block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis))
707 last_known_block_id = block_id_in_synopsis;
708 found_a_block_in_synopsis =
true;
713 if (!found_a_block_in_synopsis)
715 graphene::net::peer_is_on_an_unreachable_fork,
716 "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis");
724 result.push_back(_chain_db->get_block_id_for_num(num));
730 remaining_item_count = _chain_db->head_block_num() - block_header::num_from_id(result.back());
736 FC_CAPTURE_AND_RETHROW((blockchain_synopsis)(remaining_item_count)(limit))
742 virtual message
get_item(
const item_id&
id)
override
747 if (
id.item_type == graphene::net::block_message_type)
749 return _chain_db->with_read_lock([&]() {
750 auto opt_block = _chain_db->fetch_block_by_id(
id.item_hash);
752 elog(
"Couldn't find block ${id} -- corresponding ID in our chain is ${id2}",
753 (
"id",
id.item_hash)(
755 FC_ASSERT(opt_block.valid());
757 return block_message(std::move(*opt_block));
760 return _chain_db->with_read_lock(
761 [&]() {
return trx_message(_chain_db->get_recent_transaction(
id.item_hash)); });
763 FC_CAPTURE_AND_RETHROW((
id))
768 return _chain_db->get_chain_id();
830 uint32_t number_of_blocks_after_reference_point)
override
834 std::vector<item_hash_t> synopsis;
835 _chain_db->with_read_lock([&]() {
836 synopsis.reserve(30);
837 uint32_t high_block_num;
838 uint32_t non_fork_high_block_num;
839 uint32_t low_block_num = _chain_db->last_non_undoable_block_num();
840 std::vector<block_id_type> fork_history;
842 if (reference_point != item_hash_t())
847 if (is_included_block(reference_point))
851 assert(reference_point_block_num > 0);
852 high_block_num = reference_point_block_num;
853 non_fork_high_block_num = high_block_num;
855 if (reference_point_block_num < low_block_num)
867 low_block_num = reference_point_block_num;
875 fork_history = _chain_db->get_block_ids_on_fork(reference_point);
878 assert(fork_history.size() >= 2);
880 if (fork_history.front() != reference_point)
882 edump((fork_history)(reference_point));
883 assert(fork_history.front() == reference_point);
886 fork_history.pop_back();
887 boost::reverse(fork_history);
892 non_fork_high_block_num = 0;
899 high_block_num = non_fork_high_block_num + fork_history.size();
902 catch (
const fc::exception& e)
906 elog(
"Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}",
907 (
"hash", reference_point)(
"exception", e));
910 if (non_fork_high_block_num < low_block_num)
912 wlog(
"Unable to generate a usable synopsis because the peer we're generating it for forked "
914 "(our chains diverge after block #${non_fork_high_block_num} but only undoable to "
915 "block #${low_block_num})",
916 (
"low_block_num", low_block_num)(
"non_fork_high_block_num", non_fork_high_block_num));
917 FC_THROW_EXCEPTION(graphene::net::block_older_than_undo_history,
918 "Peer is are on a fork I'm unable to switch to");
925 high_block_num = _chain_db->head_block_num();
926 non_fork_high_block_num = high_block_num;
927 if (high_block_num == 0)
933 if (low_block_num == 0)
947 uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point;
953 if (low_block_num <= non_fork_high_block_num)
955 synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num));
959 synopsis.push_back(fork_history[low_block_num - non_fork_high_block_num - 1]);
961 low_block_num += (true_high_block_num - low_block_num + 2) / 2;
962 }
while (low_block_num <= high_block_num);
970 FC_CAPTURE_AND_RETHROW()
981 virtual void sync_status(uint32_t item_type, uint32_t item_count)
override
1000 FC_CAPTURE_AND_RETHROW((block_id))
1011 return _chain_db->with_read_lock([&]() {
1012 auto opt_block = _chain_db->fetch_block_by_id(block_id);
1013 if (opt_block.valid())
1015 return opt_block->timestamp;
1017 return fc::time_point_sec::min();
1020 FC_CAPTURE_AND_RETHROW((block_id))
1026 return fc::time_point::now();
1031 return _chain_db->with_read_lock([&]() {
return _chain_db->head_block_id(); });
1053 fc::usleep(fc::seconds(1));
1056 _p2p_network->close();
1057 fc::usleep(fc::seconds(1));
1068 FC_ASSERT(_self->_remote_endpoint,
"Write node RPC not configured properly or not currently connected.");
1069 auto ws_ptr = _self->_client.connect(*_self->_remote_endpoint);
1070 auto apic = std::make_shared<fc::rpc::websocket_api_connection>(*ws_ptr);
1071 auto login = apic->get_remote_api<
login_api>(1);
1072 FC_ASSERT(login->login(
"",
""));
1073 fc::api_ptr ret = login->get_api_by_name(api_name);
1074 FC_ASSERT(ret,
"Can't get API '${a}'.", (
"a", api_name));
1075 return ret->template as<API>();
1082 const bpo::variables_map* _options =
nullptr;
1098 int32_t _max_block_age = -1;
1103 uint32_t allow_future_time = 5;
1107 application::application()
1113 : my(new detail::application_impl(this, db))
1119 if (my->_p2p_network)
1121 my->_p2p_network->close();
1122 my->_p2p_network.reset();
1126 my->_chain_db->close();
1132 std::vector<std::string>
result;
1135 result.push_back(
"login_api");
1138 result.push_back(
"account_by_key_api");
1149 std::vector<std::string>
result;
1152 result.push_back(
"account_by_key");
1160 boost::program_options::options_description& configuration_file_options)
const
1165 const std::string str_default_apis = boost::algorithm::join(default_apis,
" ");
1166 const std::string str_default_plugins = boost::algorithm::join(default_plugins,
" ");
1169 configuration_file_options.add_options()
1170 (
"p2p-endpoint", bpo::value<std::string>(),
"Endpoint for P2P node to listen on")
1171 (
"p2p-max-connections", bpo::value<uint32_t>(),
"Maxmimum number of incoming connections on P2P endpoint")
1172 (
"seed-node,s", bpo::value<std::vector<std::string>>()->composing(),
"P2P nodes to connect to on startup (may specify multiple times)")
1173 (
"checkpoint,c", bpo::value<std::vector<std::string>>()->composing(),
"Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.")
1174 (
"data-dir,d", bpo::value<boost::filesystem::path>()->default_value(
"witness_node_data_dir"),
"Directory containing databases, configuration file, etc.")
1175 (
"shared-file-dir", bpo::value<boost::filesystem::path>(),
"Location of the shared memory file. Defaults to data_dir/blockchain")
1176 (
"shared-file-size", bpo::value<std::string>()->default_value(
"54G"),
"Size of the shared memory file. Default: 54G")
1177 (
"rpc-endpoint", bpo::value<std::string>()->implicit_value(
"127.0.0.1:8090"),
"Endpoint for websocket RPC to listen on")
1178 (
"rpc-tls-endpoint", bpo::value<std::string>()->implicit_value(
"127.0.0.1:8089"),
"Endpoint for TLS websocket RPC to listen on")
1179 (
"read-forward-rpc", bpo::value<std::string>(),
"Endpoint to forward write API calls to for a read node")
1180 (
"server-pem,p", bpo::value<std::string>()->implicit_value(
"server.pem"),
"The TLS certificate file for this server")
1181 (
"server-pem-password,P", bpo::value<std::string>()->implicit_value(
""),
"Password for this certificate")
1182 (
"api-user", bpo::value< std::vector<std::string> >()->composing(),
"API user specification, may be specified multiple times")
1183 (
"public-api", bpo::value< std::vector<std::string> >()->composing()->default_value(default_apis, str_default_apis),
"Set an API to be publicly available, may be specified multiple times")
1184 (
"enable-plugin", bpo::value< std::vector<std::string> >()->composing()->default_value(default_plugins, str_default_plugins),
"Plugin(s) to enable, may be specified multiple times")
1185 (
"max-block-age", bpo::value< int32_t >()->default_value(200),
"Maximum age of head block when broadcasting tx via API")
1186 (
"flush", bpo::value< uint32_t >()->default_value(100000),
"Flush shared memory file to disk this many blocks")
1187 (
"genesis-json,g", bpo::value<boost::filesystem::path>(),
"File to read genesis state from")
1188 (
"replay-blockchain",
"Rebuild object graph by replaying all blocks")
1189 (
"replay-skip-witness-schedule-check", bpo::value<bool>()->default_value(
true),
"Skip witness schedule check wile block replaying")
1190 (
"resync-blockchain",
"Delete all blocks and re-sync with network from scratch")
1191 (
"force-validate",
"Force validation of all transactions")
1192 (
"read-only",
"Node will not connect to p2p network and can only read from the chain state")
1193 (
"check-locks",
"Check correctness of chainbase locking")
1194 (
"disable-get-block",
"Disable get_block API call");
1198 command_line_options.add(configuration_file_options);
1199 command_line_options.add_options()(
"version,v",
"Print version number and exit.");
1201 command_line_options.add(_cli_options);
1202 configuration_file_options.add(_cfg_options);
1204 boost::program_options::options_description api_description;
1207 command_line_options.add(api_description);
1208 configuration_file_options.add(api_description);
1211 const std::string application::print_config(
const boost::program_options::variables_map& vm)
1213 namespace po = boost::program_options;
1215 std::stringstream stream;
1216 for (po::variables_map::const_iterator it = vm.begin(); it != vm.end(); it++)
1218 stream <<
"> " << it->first;
1220 if (((boost::any)it->second.value()).empty())
1222 stream <<
"(empty)";
1224 if (vm[it->first].defaulted() || it->second.defaulted())
1226 stream <<
"(default)";
1231 if (it->first ==
"server-pem-password" || it->first ==
"private-key")
1233 stream <<
"..." << std::endl;
1239 stream << vm[it->first].as<int32_t>() << std::endl;
1242 catch (
const boost::bad_any_cast&)
1248 stream << vm[it->first].as<uint32_t>() << std::endl;
1251 catch (
const boost::bad_any_cast&)
1257 stream << vm[it->first].as<
bool>() << std::endl;
1260 catch (
const boost::bad_any_cast&)
1266 stream << vm[it->first].as<
double>() << std::endl;
1269 catch (
const boost::bad_any_cast&)
1275 stream << vm[it->first].as<boost::filesystem::path>().
string() << std::endl;
1278 catch (
const boost::bad_any_cast&)
1284 std::string temp = vm[it->first].as<std::string>();
1287 stream << temp << std::endl;
1291 stream <<
"true" << std::endl;
1295 catch (
const boost::bad_any_cast&)
1302 auto vect = vm[it->first].as<std::vector<std::string>>();
1304 for (
auto oit = vect.begin(); oit != vect.end(); ++oit, ++i)
1306 stream <<
"\r> " << it->first <<
"[" << i <<
"]=" << (*oit) << std::endl;
1309 catch (
const boost::bad_any_cast&)
1311 stream <<
"UnknownType(" << ((boost::any)it->second.value()).type().name() <<
")" << std::endl;
1315 return stream.str();
1320 ilog(
"initializing node with config:\n${config}", (
"config", print_config(options)));
1322 my->_options = &options;
1332 _read_only = my->_options->count(
"read-only");
1335 catch (
const fc::exception& e)
1337 elog(
"${e}", (
"e", e.to_detail_string()));
1342 elog(
"unexpected exception");
1351 return my->_plugins_enabled.at(name);
1362 return my->_p2p_network;
1367 return my->_chain_db;
1372 my->_is_block_producer = producing_blocks;
1377 return my->get_api_access_info(username);
1382 my->set_api_access_info(username, std::move(permissions));
1387 return my->register_api_factory(name, factory);
1392 return my->create_api_by_name(ctx);
1397 my->get_max_block_age(
result);
1411 for (
auto& entry : my->_plugins_enabled)
1413 entry.second->plugin_shutdown();
1425 using boost::program_options::options_description;
1427 options_description plugin_cli_options(
"Options for plugin " + plug->plugin_name()), plugin_cfg_options;
1428 plug->plugin_set_program_options(plugin_cli_options, plugin_cfg_options);
1430 if (!plugin_cli_options.options().empty())
1432 _cli_options.add(plugin_cli_options);
1435 if (!plugin_cfg_options.options().empty())
1437 _cfg_options.add(plugin_cfg_options);
1440 my->_plugins_available[plug->plugin_name()] = plug;
1445 auto it = my->_plugins_available.find(name);
1446 if (it == my->_plugins_available.end())
1448 elog(
"can't enable plugin ${name}", (
"name", name));
1450 FC_ASSERT(it != my->_plugins_available.end());
1451 my->_plugins_enabled[name] = it->second;
1456 if (options.count(
"enable-plugin") > 0)
1458 for (
auto& arg : options.at(
"enable-plugin").as<std::vector<std::string>>())
1460 std::vector<std::string> names;
1461 boost::split(names, arg, boost::is_any_of(
" \t,"));
1462 for (
const std::string& name : names)
1473 bool read_only = options.count(
"read-only");
1474 for (
auto& entry : my->_plugins_enabled)
1476 const auto& plugin_name = entry.first;
1479 && my->_plugins_locked_in_readonly_mode.find(plugin_name) != my->_plugins_locked_in_readonly_mode.end())
1481 ilog(
"Skip ${p} plugin initialization in read-only mode", (
"p", plugin_name));
1485 ilog(
"Initializing plugin ${name}", (
"name", plugin_name));
1486 entry.second->plugin_initialize(options);
1492 for (
auto& entry : my->_plugins_enabled)
1494 entry.second->plugin_startup();
1502 std::cout <<
"scorum_git_revision: " << fc::string(graphene::utilities::git_revision_sha) <<
"\n";
1503 std::cout <<
"fc_git_revision: " << fc::string(fc::git_revision_sha) <<
"\n";
1504 std::cout <<
"embeded_chain_id " << egenesis::get_egenesis_chain_id().str() <<
"\n";
1509 for (
const boost::shared_ptr<bpo::option_description> od : options.options())
1511 if (!od->description().empty())
1512 stream <<
"# " << od->description() <<
"\n";
1515 if (!od->semantic()->apply_default(store))
1517 stream <<
"# " << od->long_name() <<
" = \n";
1521 auto example = od->format_parameter();
1522 if (example.empty())
1525 stream << od->long_name() <<
" = "
1531 example.erase(0, 6);
1532 example.erase(example.length() - 1);
1533 stream << od->long_name() <<
" = " << example <<
"\n";
1542 namespace bfs = boost::filesystem;
1544 FC_ASSERT(options.count(
"data-dir"),
"Default value for 'data-dir' should be set.");
1546 return bfs::absolute(options[
"data-dir"].as<bfs::path>());
1551 namespace bfs = boost::filesystem;
1555 if (options.count(
"config-file"))
1557 config_ini_path = bfs::absolute(options[
"config-file"].as<bfs::path>());
1560 return config_ini_path;
1564 const boost::program_options::options_description& cfg_options)
1566 FC_ASSERT(config_ini_path.is_absolute(),
"config-file path should be absolute");
1568 if (!fc::exists(config_ini_path))
1570 ilog(
"Writing new config file at ${path}", (
"path", config_ini_path));
1571 if (!fc::exists(config_ini_path.parent_path()))
1573 fc::create_directories(config_ini_path.parent_path());
1576 std::ofstream out_cfg(config_ini_path.preferred_string());
#define API_ACCOUNT_HISTORY
#define API_ACCOUNT_STATISTICS
#define ACCOUNT_STATISTICS_PLUGIN_NAME
#define ADVERTISING_API_NAME
#define SCORUMD_CONFIG_FILE_NAME
#define API_BLOCKCHAIN_HISTORY
#define BLOCKCHAIN_HISTORY_PLUGIN_NAME
#define BLOCKCHAIN_MONITORING_PLUGIN_NAME
#define API_BLOCKCHAIN_STATISTICS
std::vector< std::string > get_default_apis() const
void set_block_production(bool producing_blocks)
void enable_plugin(const std::string &name)
std::shared_ptr< chain::database > chain_database() const
fc::optional< fc::api< network_broadcast_api > > _remote_net_api
void initialize(const boost::program_options::variables_map &options)
std::shared_ptr< abstract_plugin > get_plugin(const std::string &name) const
bool is_read_only() const
void set_program_options(boost::program_options::options_description &command_line_options, boost::program_options::options_description &configuration_file_options) const
graphene::net::node_ptr p2p_node()
void register_abstract_plugin(std::shared_ptr< abstract_plugin > plug)
fc::api< network_broadcast_api > & get_write_node_net_api()
std::vector< std::string > get_default_plugins() const
fc::optional< api_access_info > get_api_access_info(const std::string &username) const
void register_api_factory(const std::string &name, std::function< fc::api_ptr(const api_context &)> factory)
fc::api_ptr create_api_by_name(const api_context &ctx)
void get_max_block_age(int32_t &result)
void set_api_access_info(const std::string &username, api_access_info &&permissions)
fc::optional< std::string > _remote_endpoint
void initialize_plugins(const boost::program_options::variables_map &options)
The chain_api class shows blockchain entrails.
virtual void error_encountered(const std::string &message, const fc::oexception &error) override
virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override
virtual void handle_message(const message &message_to_process) override
application_impl(application *self, std::shared_ptr< chain::database > chain_db)
virtual message get_item(const item_id &id) override
std::shared_ptr< fc::http::websocket_server > _websocket_server
fc::optional< fc::temp_file > _lock_file
flat_map< std::string, std::function< fc::api_ptr(const api_context &)> > _api_factories_by_name
void compute_genesis_state(scorum::chain::genesis_state_type &genesis_state)
virtual uint32_t get_block_number(const item_hash_t &block_id) override
uint64_t _shared_file_size
void register_builtin_apis()
virtual void sync_status(uint32_t item_type, uint32_t item_count) override
virtual std::vector< item_hash_t > get_blockchain_synopsis(const item_hash_t &reference_point, uint32_t number_of_blocks_after_reference_point) override
void on_connection(const fc::http::websocket_connection_ptr &c)
std::shared_ptr< fc::http::websocket_tls_server > _websocket_tls_server
virtual fc::time_point_sec get_blockchain_now() override
std::vector< std::string > _public_apis
void get_max_block_age(int32_t &result)
plugins_type _plugins_enabled
virtual chain_id_type get_chain_id() const override
fc::api< API > create_write_node_api(const std::string &api_name)
plugins_type _plugins_available
optional< api_access_info > get_api_access_info(const std::string &username) const
fc::api_ptr create_api_by_name(const api_context &ctx)
bool is_included_block(const block_id_type &block_id)
void set_api_access_info(const std::string &username, api_access_info &&permissions)
virtual bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode, std::vector< fc::uint160_t > &contained_transaction_message_ids) override
allows the application to validate an item prior to broadcasting to peers.
void register_api_factory(const std::string &name, std::function< fc::api_ptr(const api_context &)> factory)
virtual void connection_count_changed(uint32_t c) override
const bpo::variables_map * _options
virtual void handle_transaction(const graphene::net::trx_message &transaction_message) override
void reset_websocket_server()
std::shared_ptr< scorum::chain::database > _chain_db
virtual item_hash_t get_head_block_id() const override
std::vector< fc::ip::endpoint > resolve_string_to_ip_endpoints(const std::string &endpoint_string)
void reset_websocket_tls_server()
void reset_p2p_node(const fc::path &data_dir)
virtual std::vector< item_hash_t > get_block_ids(const std::vector< item_hash_t > &blockchain_synopsis, uint32_t &remaining_item_count, uint32_t limit) override
uint32_t allow_future_time
virtual fc::time_point_sec get_block_time(const item_hash_t &block_id) override
virtual bool has_item(const graphene::net::item_id &id) override
std::shared_ptr< graphene::net::node > _p2p_network
The login_api class implements the bottom layer of the RPC API.
The network_broadcast_api class allows broadcasting of transactions.
The network_node_api class allows maintenance of p2p connections.
tracks the blockchain state in an extensible manner
@ skip_validate_invariants
used to skip database invariant check on block application
@ skip_transaction_signatures
used by non-witness nodes
void set_options(const boost::program_options::variables_map &options)
boost::program_options::options_description get_options_descriptions() const
#define SCORUM_BLOCKCHAIN_VERSION
std::map< std::string, std::shared_ptr< abstract_plugin > > plugins_type
std::set< std::string > plugin_names_type
void print_program_options(std::ostream &stream, const boost::program_options::options_description &options)
void print_application_version()
fc::path get_data_dir_path(const boost::program_options::variables_map &options)
void create_config_file_if_not_exist(const fc::path &config_ini_path, const boost::program_options::options_description &cfg_options)
fc::path get_config_file_path(const boost::program_options::variables_map &options)
fc::ripemd160 block_id_type
config_api & get_api_config(std::string api_name)
std::string password_salt_b64
std::string password_hash_b64
std::vector< std::string > allowed_apis
std::map< std::string, api_access_info > permission_map
api_context(application &_app, const std::string &_api_name, std::weak_ptr< api_session_data > _session)
chain_id_type initial_chain_id