34 #include <boost/filesystem/path.hpp>
42 namespace bpo = boost::program_options;
47 "********************************\n"
49 "* ------- NEW CHAIN ------ *\n"
50 "* - Welcome to BitShares! - *\n"
51 "* ------------------------ *\n"
53 "********************************\n"
57 wlog(
"Your genesis seems to have an old timestamp");
58 wlog(
"Please consider using the --genesis-timestamp option to give your genesis a recent timestamp");
62 void witness_plugin::plugin_set_program_options(
63 boost::program_options::options_description& command_line_options,
64 boost::program_options::options_description& config_file_options)
68 command_line_options.add_options()
69 (
"enable-stale-production", bpo::bool_switch()->notifier([
this](
bool e){_production_enabled = e;}),
70 "Enable block production, even if the chain is stale.")
71 (
"required-participation", bpo::value<uint32_t>()->default_value(33),
72 "Percent of witnesses (0-100) that must be participating in order to produce blocks")
73 (
"witness-id,w", bpo::value<vector<string>>()->composing()->multitoken(),
74 (
"ID of witness controlled by this node (e.g. " + witness_id_example +
75 ", quotes are required, may specify multiple times)").c_str())
76 (
"private-key", bpo::value<vector<string>>()->composing()->multitoken()->
79 "Tuple of [PublicKey, WIF private key] (may specify multiple times)")
80 (
"private-key-file", bpo::value<vector<boost::filesystem::path>>()->composing()->multitoken(),
81 "Path to a file containing tuples of [PublicKey, WIF private key]."
82 " The file has to contain exactly one tuple (i.e. private - public key pair) per line."
83 " This option may be specified multiple times, thus multiple files can be provided.")
85 config_file_options.add(command_line_options);
88 std::string witness_plugin::plugin_name()
const
93 void witness_plugin::add_private_key(
const std::string& key_id_to_wif_pair_string)
95 auto key_id_to_wif_pair = graphene::app::dejsonify<std::pair<chain::public_key_type, std::string>>
96 (key_id_to_wif_pair_string, 5);
108 FC_THROW(
"Invalid WIF-format private key ${key_string}", (
"key_string", key_id_to_wif_pair.second));
112 if (_private_keys.find(key_id_to_wif_pair.first) == _private_keys.end())
114 ilog(
"Public Key: ${public}", (
"public", key_id_to_wif_pair.first));
115 _private_keys[key_id_to_wif_pair.first] = *private_key;
119 void witness_plugin::plugin_initialize(
const boost::program_options::variables_map& options)
121 ilog(
"witness plugin: plugin_initialize() begin");
123 LOAD_VALUE_SET(options,
"witness-id", _witnesses, chain::witness_id_type);
125 if( options.count(
"private-key") > 0 )
127 const std::vector<std::string> key_id_to_wif_pair_strings = options[
"private-key"].as<std::vector<std::string>>();
128 for (
const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
130 add_private_key(key_id_to_wif_pair_string);
133 if (options.count(
"private-key-file") > 0)
135 const std::vector<boost::filesystem::path> key_id_to_wif_pair_files =
136 options[
"private-key-file"].as<std::vector<boost::filesystem::path>>();
137 for (
const boost::filesystem::path& key_id_to_wif_pair_file : key_id_to_wif_pair_files)
141 std::string file_content;
143 std::istringstream file_content_as_stream(file_content);
148 add_private_key(line);
153 FC_THROW(
"Failed to load private key file from ${path}", (
"path", key_id_to_wif_pair_file.string()));
157 if(options.count(
"required-participation") > 0)
159 auto required_participation = options[
"required-participation"].as<uint32_t>();
160 FC_ASSERT(required_participation <= 100);
161 _required_witness_participation = options[
"required-participation"].as<uint32_t>()*
GRAPHENE_1_PERCENT;
162 if(required_participation < 10)
163 wlog(
"witness plugin: Warning - Low required participation of ${rp}% found", (
"rp", required_participation));
164 else if(required_participation > 90)
165 wlog(
"witness plugin: Warning - High required participation of ${rp}% found", (
"rp", required_participation));
167 ilog(
"witness plugin: plugin_initialize() end");
170 void witness_plugin::plugin_startup()
172 ilog(
"witness plugin: plugin_startup() begin");
174 if( !_witnesses.empty() )
176 ilog(
"Launching block production for ${n} witnesses.", (
"n", _witnesses.size()));
178 if( _production_enabled )
184 refresh_witness_key_cache();
187 refresh_witness_key_cache();
189 schedule_production_loop();
193 ilog(
"No witness configured.");
195 ilog(
"witness plugin: plugin_startup() end");
198 void witness_plugin::stop_block_production()
200 _shutting_down =
true;
203 if( _block_production_task.
valid() )
205 }
catch(fc::canceled_exception&) {
212 void witness_plugin::refresh_witness_key_cache()
215 for(
const chain::witness_id_type& wit_id : _witnesses )
225 void witness_plugin::schedule_production_loop()
227 if (_shutting_down)
return;
233 if( time_to_next_second < 50000 )
234 time_to_next_second += 1000000;
238 _block_production_task =
fc::schedule([
this]{block_production_loop();},
239 next_wakeup,
"Witness Block Production");
255 result = maybe_produce_block(capture);
257 catch(
const fc::canceled_exception& )
272 ilog(
"Generated block #${n} with ${x} transaction(s) and timestamp ${t} at time ${c}", (capture));
275 ilog(
"Not producing block because production is disabled until we receive a recent block "
276 "(see: --enable-stale-production)");
283 ilog(
"Not producing block because I don't have the private key for ${scheduled_key}", (capture) );
286 elog(
"Not producing block because node appears to be on a minority fork with only ${pct}% witness participation",
290 elog(
"Not producing block because node didn't wake up within 2500ms of the slot time.");
293 elog(
"exception producing block" );
296 ilog(
"shutdown producing block" );
299 ilog(
"not connected to P2P network" );
302 elog(
"unknown condition ${result} while producing block", (
"result", (
unsigned char)result) );
306 schedule_production_loop();
318 if( !_production_enabled )
320 if( db.get_slot_time(1) >= now )
321 _production_enabled =
true;
327 uint32_t slot = db.get_slot_at_time( now );
330 capture(
"next_time", db.get_slot_time(1));
342 assert( now > db.head_block_time() );
344 graphene::chain::witness_id_type scheduled_witness = db.get_scheduled_witness( slot );
346 if( _witnesses.find( scheduled_witness ) == _witnesses.end() )
348 capture(
"scheduled_witness", scheduled_witness);
354 auto private_key_itr = _private_keys.find( scheduled_key );
356 if( private_key_itr == _private_keys.end() )
358 capture(
"scheduled_key", scheduled_key);
362 uint32_t prate = db.witness_participation_rate();
363 if( prate < _required_witness_participation )
369 if( llabs((scheduled_time - now).count()) >
fc::milliseconds( 2500 ).count() )
371 capture(
"scheduled_time", scheduled_time)(
"now", now);
378 auto block = db.generate_block(
381 private_key_itr->second,
382 _production_skip_flags
384 capture(
"n", block.block_num())(
"t", block.timestamp)(
"c", now)(
"x", block.transactions.size());
385 fc::async( [
this,block](){
p2p_node()->broadcast(net::block_message(block)); } );