diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 09126702..f615fd59 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -54,6 +54,35 @@ namespace bpo = boost::program_options; namespace detail { + genesis_state_type create_example_genesis() { + auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan"))); + dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key))); + genesis_state_type initial_state; + fc::reflector::visit( + fee_schedule_type::fee_set_visitor{initial_state.initial_parameters.current_fees, 0}); + secret_hash_type::encoder enc; + fc::raw::pack(enc, nathan_key); + fc::raw::pack(enc, secret_hash_type()); + auto secret = secret_hash_type::hash(enc.result()); + initial_state.initial_active_witnesses = 10; + for( int i = 0; i < initial_state.initial_active_witnesses; ++i ) + { + auto name = "init"+fc::to_string(i); + initial_state.initial_accounts.emplace_back(name, + nathan_key.get_public_key(), + nathan_key.get_public_key(), + true); + initial_state.initial_committee_candidates.push_back({name}); + initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key(), secret}); + } + + initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key()); + initial_state.initial_balances.push_back({nathan_key.get_public_key(), + GRAPHENE_SYMBOL, + GRAPHENE_MAX_SHARE_SUPPLY}); + return initial_state; + } + class application_impl : public net::node_delegate { public: @@ -107,7 +136,7 @@ namespace detail { wsc->register_api(fc::api(login)); c->set_session_data( wsc ); }); - ilog("Configured websocket rpc to listen on ${ip}", ("ip",_options->at("rpc-endpoint").as())); + ilog("Configured websocket rpc to listen on ${ip}", ("ip",_options->at("rpc-endpoint").as())); _websocket_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-endpoint").as()) ); _websocket_server->start_accept(); } FC_CAPTURE_AND_RETHROW() } @@ -134,7 +163,7 @@ namespace detail { wsc->register_api(fc::api(login)); c->set_session_data( wsc ); }); - ilog("Configured websocket TLS rpc to listen on ${ip}", ("ip",_options->at("rpc-tls-endpoint").as())); + ilog("Configured websocket TLS rpc to listen on ${ip}", ("ip",_options->at("rpc-tls-endpoint").as())); _websocket_tls_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-tls-endpoint").as()) ); _websocket_tls_server->start_accept(); } FC_CAPTURE_AND_RETHROW() } @@ -155,34 +184,12 @@ namespace detail { bool clean = !fc::exists(_data_dir / "blockchain/dblock"); fc::create_directories(_data_dir / "blockchain/dblock"); - auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan"))); genesis_state_type initial_state; - fc::reflector::visit( - fee_schedule_type::fee_set_visitor{initial_state.initial_parameters.current_fees, 0}); - secret_hash_type::encoder enc; - fc::raw::pack(enc, nathan_key); - fc::raw::pack(enc, secret_hash_type()); - auto secret = secret_hash_type::hash(enc.result()); - for( int i = 0; i < 10; ++i ) - { - auto name = "init"+fc::to_string(i); - initial_state.initial_accounts.emplace_back(name, - nathan_key.get_public_key(), - nathan_key.get_public_key(), - true); - initial_state.initial_committee_candidates.push_back({name}); - initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key(), secret}); - } - - initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key()); - initial_state.initial_balances.push_back({nathan_key.get_public_key(), - GRAPHENE_SYMBOL, - GRAPHENE_MAX_SHARE_SUPPLY}); if( _options->count("genesis-json") ) initial_state = fc::json::from_file(_options->at("genesis-json").as()) .as(); else - dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key))); + initial_state = create_example_genesis(); if( _options->count("resync-blockchain") ) _chain_db->wipe(_data_dir / "blockchain", true); @@ -427,13 +434,11 @@ application::~application() { if( my->_p2p_network ) { - //ilog("Closing p2p node"); my->_p2p_network->close(); my->_p2p_network.reset(); } if( my->_chain_db ) { - //ilog("Closing chain database"); my->_chain_db->close(); } } @@ -452,6 +457,10 @@ void application::set_program_options(boost::program_options::options_descriptio ; command_line_options.add(configuration_file_options); command_line_options.add_options() + ("create-genesis-json", bpo::value(), + "Path to create a Genesis State at. If a well-formed JSON file exists at the path, it will be parsed and any " + "missing fields in a Genesis State will be added, and any unknown fields will be removed. If no file or an " + "invalid file is found, it will be replaced with an example Genesis State.") ("replay-blockchain", "Rebuild object graph by replaying all blocks") ("resync-blockchain", "Delete all blocks and re-sync with network from scratch") ; @@ -463,6 +472,31 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti { my->_data_dir = data_dir; my->_options = &options; + + if( options.count("create-genesis-json") ) + { + fc::path genesis_out = options.at("create-genesis-json").as(); + genesis_state_type genesis_state = detail::create_example_genesis(); + if( fc::exists(genesis_out) ) + { + try { + genesis_state = fc::json::from_file(genesis_out).as(); + } catch(const fc::exception& e) { + std::cerr << "Unable to parse existing genesis file:\n" << e.to_string() + << "\nWould you like to replace it? [y/N] "; + char response = std::cin.get(); + if( toupper(response) != 'Y' ) + return; + } + + std::cerr << "Updating genesis state in file " << genesis_out.generic_string() << "\n"; + } else { + std::cerr << "Creating example genesis state in file " << genesis_out.generic_string() << "\n"; + } + fc::json::save_to_file(genesis_state, genesis_out); + + std::exit(EXIT_SUCCESS); + } } void application::startup() diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 603b12d7..8fb62226 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -251,24 +251,12 @@ void database::init_genesis(const genesis_state_type& genesis_state) // Create initial accounts for( const auto& account : genesis_state.initial_accounts ) { - /* - key_id_type key_id = apply_operation(genesis_eval_state, - key_create_operation({asset(), - GRAPHENE_TEMP_ACCOUNT, - account.owner_key})).get(); - */ account_create_operation cop; cop.name = account.name; cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, account.owner_key, 1); if( account.owner_key != account.active_key ) { - /* - key_id = apply_operation(genesis_eval_state, - key_create_operation({asset(), - GRAPHENE_TEMP_ACCOUNT, - account.owner_key})).get(); - */ cop.active = authority(1, account.owner_key, 1); } else { cop.active = cop.owner; @@ -288,7 +276,9 @@ void database::init_genesis(const genesis_state_type& genesis_state) const auto& accounts_by_name = get_index_type().indices().get(); auto get_account_id = [&accounts_by_name](const string& name) { auto itr = accounts_by_name.find(name); - FC_ASSERT(itr != accounts_by_name.end()); + FC_ASSERT(itr != accounts_by_name.end(), + "Unable to find account '${acct}'. Did you forget to add a record for it to initial_accounts?", + ("acct", name)); return itr->get_id(); }; @@ -296,7 +286,9 @@ void database::init_genesis(const genesis_state_type& genesis_state) const auto& assets_by_symbol = get_index_type().indices().get(); auto get_asset_id = [&assets_by_symbol](const string& symbol) { auto itr = assets_by_symbol.find(symbol); - FC_ASSERT(itr != assets_by_symbol.end()); + FC_ASSERT(itr != assets_by_symbol.end(), + "Unable to find asset '${sym}'. Did you forget to add a record for it to initial_assets?", + ("sym", symbol)); return itr->get_id(); }; @@ -313,12 +305,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) int collateral_holder_number = 0; for( const auto& collateral_rec : asset.bitasset_options->collateral_records ) { - /* - key_id_type key_id = apply_operation(genesis_eval_state, - key_create_operation{{}, - GRAPHENE_TEMP_ACCOUNT, - collateral_rec.owner}).get(); - */ account_create_operation cop; cop.name = asset.symbol + "-collateral-holder-" + std::to_string(collateral_holder_number); boost::algorithm::to_lower(cop.name); @@ -414,11 +400,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) // Create initial witnesses and delegates std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { - /* - const key_object& signing_key = create([&witness](key_object& k) { - k.key_data = witness.block_signing_key; - }); - */ witness_create_operation op; op.block_signing_key = witness.block_signing_key; diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index eca76d97..05593da4 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -36,10 +36,11 @@ void witness_plugin::plugin_set_program_options( boost::program_options::options_description& config_file_options) { auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan"))); + string witness_id_example = fc::json::to_string(chain::witness_id_type()); command_line_options.add_options() ("enable-stale-production", bpo::bool_switch()->notifier([this](bool e){_production_enabled = e;}), "Enable block production, even if the chain is stale") ("witness-id,w", bpo::value>()->composing()->multitoken(), - "ID of witness controlled by this node (e.g. \"1.7.0\", quotes are required, may specify multiple times)") + ("ID of witness controlled by this node (e.g. " + witness_id_example + ", quotes are required, may specify multiple times)").c_str()) ("private-key", bpo::value>()->composing()->multitoken()-> DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), "Tuple of [PublicKey, WIF private key] (may specify multiple times)") @@ -56,9 +57,9 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m { try { _options = &options; LOAD_VALUE_SET(options, "witness-id", _witnesses, chain::witness_id_type) - - if( options.count("private-key") ) - { + + if( options.count("private-key") ) + { const std::vector key_id_to_wif_pair_strings = options["private-key"].as>(); for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings) { diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 9e48dff7..b72688ed 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -981,6 +981,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) fc::temp_directory td; genesis_state.initial_balances.push_back({generate_private_key("n").get_public_key(), GRAPHENE_SYMBOL, 1}); genesis_state.initial_balances.push_back({generate_private_key("x").get_public_key(), GRAPHENE_SYMBOL, 1}); +// genesis_state.initial_vesting_balances.push_back({generate_private_key("v").get_public_key(), GRAPHENE_SYMBOL, 1}); // TODO: vesting genesis balances genesis_state.initial_accounts.emplace_back("n", generate_private_key("n").get_public_key());