diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index c80cec92c..cd20cd818 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -82,7 +82,7 @@ uint64_t blockchain_storage::get_current_blockchain_height() return m_blocks.size(); } //------------------------------------------------------------------ -bool blockchain_storage::init(const std::string& config_folder) +bool blockchain_storage::init(const std::string& config_folder, bool testnet) { CRITICAL_REGION_LOCAL(m_blockchain_lock); m_config_folder = config_folder; @@ -121,11 +121,24 @@ bool blockchain_storage::init(const std::string& config_folder) if(!m_blocks.size()) { LOG_PRINT_L0("Blockchain not loaded, generating genesis block."); - block bl = boost::value_initialized(); - block_verification_context bvc = boost::value_initialized(); - generate_genesis_block(bl); - add_new_block(bl, bvc); - CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain"); + + if (!store_genesis_block(testnet)) { + return false; + } + } else { + cryptonote::block b; + if (testnet) { + generate_testnet_genesis_block(b); + } else { + generate_genesis_block(b); + } + + crypto::hash genesis_hash = get_block_hash(m_blocks[0].bl); + crypto::hash testnet_genesis_hash = get_block_hash(b); + if (genesis_hash != testnet_genesis_hash) { + LOG_ERROR("Failed to init: genesis block mismatch. Probably you set --testnet flag with data dir with non-test blockchain or another network."); + return false; + } } uint64_t timestamp_diff = time(NULL) - m_blocks.back().bl.timestamp; if(!m_blocks.back().bl.timestamp) @@ -134,6 +147,21 @@ bool blockchain_storage::init(const std::string& config_folder) return true; } //------------------------------------------------------------------ +bool blockchain_storage::store_genesis_block(bool testnet) { + block bl = ::boost::value_initialized(); + block_verification_context bvc = boost::value_initialized(); + + if (testnet) { + generate_testnet_genesis_block(bl); + } else { + generate_genesis_block(bl); + } + + add_new_block(bl, bvc); + CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain"); + return true; +} +//------------------------------------------------------------------ bool blockchain_storage::store_blockchain() { m_is_blockchain_storing = true; diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index 55c0cb77e..0f7295516 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -81,8 +81,8 @@ namespace cryptonote blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false) {}; - bool init() { return init(tools::get_default_data_dir()); } - bool init(const std::string& config_folder); + bool init() { return init(tools::get_default_data_dir(), true); } + bool init(const std::string& config_folder, bool testnet = false); bool deinit(); void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; } @@ -242,6 +242,7 @@ namespace cryptonote uint64_t get_adjusted_time(); bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); bool update_next_comulative_size_limit(); + bool store_genesis_block(bool testnet); }; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 637b8fea6..3ff139c95 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -116,14 +116,14 @@ namespace cryptonote return m_blockchain_storage.get_alternative_blocks_count(); } //----------------------------------------------------------------------------------------------- - bool core::init(const boost::program_options::variables_map& vm) + bool core::init(const boost::program_options::variables_map& vm, bool testnet) { bool r = handle_command_line(vm); r = m_mempool.init(m_config_folder); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); - r = m_blockchain_storage.init(m_config_folder); + r = m_blockchain_storage.init(m_config_folder, testnet); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); r = m_miner.init(vm); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 704a65cf1..f050431ef 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -70,7 +70,7 @@ namespace cryptonote miner& get_miner(){return m_miner;} static void init_options(boost::program_options::options_description& desc); - bool init(const boost::program_options::variables_map& vm); + bool init(const boost::program_options::variables_map& vm, bool testnet); bool set_genesis_block(const block& b); bool deinit(); uint64_t get_current_blockchain_height(); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index d023561c3..47cd0e159 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -686,6 +686,16 @@ namespace cryptonote miner::find_nonce_for_given_block(bl, 1, 0); return true; } + + bool generate_testnet_genesis_block(cryptonote::block& b) { + if (!generate_genesis_block(b)) { + return false; + } + + b.nonce += 1; + return true; + } + //--------------------------------------------------------------- bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height) { diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 9ed6c10a4..4457f6cc6 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -106,6 +106,7 @@ namespace cryptonote bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height); crypto::hash get_block_longhash(const block& b, uint64_t height); bool generate_genesis_block(block& bl); + bool generate_testnet_genesis_block(block& bl); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); uint64_t get_outs_money_amount(const transaction& tx); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 187970359..1041aa439 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -62,6 +62,8 @@ namespace const command_line::arg_descriptor arg_log_file = {"log-file", "", ""}; const command_line::arg_descriptor arg_log_level = {"log-level", "", LOG_LEVEL_0}; const command_line::arg_descriptor arg_console = {"no-console", "Disable daemon console commands"}; + const command_line::arg_descriptor arg_testnet_on = {"testnet", "Used to deploy test nets. Checkpoints and hardcoded seeds are ignored, " + "network id is changed. Use it with --data-dir flag. The wallet must be launched with --testnet flag.", false}; } bool command_line_preprocessor(const boost::program_options::variables_map& vm) @@ -123,7 +125,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, arg_log_file); command_line::add_arg(desc_cmd_sett, arg_log_level); command_line::add_arg(desc_cmd_sett, arg_console); - + command_line::add_arg(desc_cmd_sett, arg_testnet_on); cryptonote::core::init_options(desc_cmd_sett); cryptonote::core_rpc_server::init_options(desc_cmd_sett); @@ -191,7 +193,14 @@ int main(int argc, char* argv[]) //create objects and link them cryptonote::core ccore(NULL); - ccore.set_checkpoints(std::move(checkpoints)); + + bool testnet_mode = command_line::get_arg(vm, arg_testnet_on); + if (testnet_mode) { + LOG_PRINT_L0("Starting in testnet mode!"); + } else { + ccore.set_checkpoints(std::move(checkpoints)); + } + cryptonote::t_cryptonote_protocol_handler cprotocol(ccore, NULL); nodetool::node_server > p2psrv(cprotocol); cryptonote::core_rpc_server rpc_server(ccore, p2psrv); @@ -201,7 +210,7 @@ int main(int argc, char* argv[]) //initialize objects LOG_PRINT_L0("Initializing P2P server..."); - res = p2psrv.init(vm); + res = p2psrv.init(vm, testnet_mode); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize P2P server."); LOG_PRINT_L0("P2P server initialized OK"); @@ -217,7 +226,7 @@ int main(int argc, char* argv[]) //initialize core here LOG_PRINT_L0("Initializing core..."); - res = ccore.init(vm); + res = ccore.init(vm, testnet_mode); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); LOG_PRINT_L0("Core initialized OK"); diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index d7576d5dd..bca18c906 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -79,13 +79,13 @@ namespace nodetool public: typedef t_payload_net_handler payload_net_handler; // Some code - node_server(t_payload_net_handler& payload_handler):m_payload_handler(payload_handler), m_allow_local_ip(false), m_hide_my_port(false) + node_server(t_payload_net_handler& payload_handler):m_payload_handler(payload_handler), m_allow_local_ip(false), m_hide_my_port(false), m_network_id(MONERO_NETWORK) {} static void init_options(boost::program_options::options_description& desc); bool run(); - bool init(const boost::program_options::variables_map& vm); + bool init(const boost::program_options::variables_map& vm, bool testnet); bool deinit(); bool send_stop_signal(); uint32_t get_this_peer_port(){return m_listenning_port;} @@ -229,6 +229,7 @@ namespace nodetool uint64_t m_peer_livetime; //keep connections to initiate some interactions net_server m_net_server; + boost::uuids::uuid m_network_id; }; } diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ee401ce42..211f5064a 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -224,19 +224,23 @@ namespace nodetool #define ADD_HARDCODED_SEED_NODE(addr) append_net_address(m_seed_nodes, addr); //----------------------------------------------------------------------------------- template - bool node_server::init(const boost::program_options::variables_map& vm) + bool node_server::init(const boost::program_options::variables_map& vm, bool testnet) { - ADD_HARDCODED_SEED_NODE("62.210.78.186:18080"); - ADD_HARDCODED_SEED_NODE("195.12.60.154:18080"); - ADD_HARDCODED_SEED_NODE("54.241.246.125:18080"); - ADD_HARDCODED_SEED_NODE("107.170.157.169:18080"); - ADD_HARDCODED_SEED_NODE("54.207.112.216:18080"); - ADD_HARDCODED_SEED_NODE("78.27.112.54:18080"); - ADD_HARDCODED_SEED_NODE("209.222.30.57:18080"); - ADD_HARDCODED_SEED_NODE("80.71.13.55:18080"); - ADD_HARDCODED_SEED_NODE("107.178.112.126:18080"); - ADD_HARDCODED_SEED_NODE("107.158.233.98:18080"); - ADD_HARDCODED_SEED_NODE("64.22.111.2:18080"); + if (!testnet) { + ADD_HARDCODED_SEED_NODE("62.210.78.186:18080"); + ADD_HARDCODED_SEED_NODE("195.12.60.154:18080"); + ADD_HARDCODED_SEED_NODE("54.241.246.125:18080"); + ADD_HARDCODED_SEED_NODE("107.170.157.169:18080"); + ADD_HARDCODED_SEED_NODE("54.207.112.216:18080"); + ADD_HARDCODED_SEED_NODE("78.27.112.54:18080"); + ADD_HARDCODED_SEED_NODE("209.222.30.57:18080"); + ADD_HARDCODED_SEED_NODE("80.71.13.55:18080"); + ADD_HARDCODED_SEED_NODE("107.178.112.126:18080"); + ADD_HARDCODED_SEED_NODE("107.158.233.98:18080"); + ADD_HARDCODED_SEED_NODE("64.22.111.2:18080"); + } else { + m_network_id.data[0] += 1; + } bool res = handle_command_line(vm); CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line"); @@ -410,7 +414,7 @@ namespace nodetool return; } - if(rsp.node_data.network_id != MONERO_NETWORK) + if(rsp.node_data.network_id != m_network_id) { LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong network! (" << epee::string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection."); return; @@ -818,7 +822,7 @@ namespace nodetool node_data.my_port = m_external_port ? m_external_port : m_listenning_port; else node_data.my_port = 0; - node_data.network_id = MONERO_NETWORK; + node_data.network_id = m_network_id; return true; } //----------------------------------------------------------------------------------- @@ -1038,7 +1042,7 @@ namespace nodetool template int node_server::handle_handshake(int command, typename COMMAND_HANDSHAKE::request& arg, typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context) { - if(arg.node_data.network_id != MONERO_NETWORK) + if(arg.node_data.network_id != m_network_id) { LOG_PRINT_CCONTEXT_L1("WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id)); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index e822e6636..4312981e2 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -72,6 +72,7 @@ namespace const command_line::arg_descriptor arg_non_deterministic = {"non-deterministic", "creates non-deterministic view and spend keys", false}; const command_line::arg_descriptor arg_daemon_port = {"daemon-port", "Use daemon instance at port instead of 8081", 0}; const command_line::arg_descriptor arg_log_level = {"set_log", "", 0, true}; + const command_line::arg_descriptor arg_testnet = {"testnet", "Used to deploy test nets. The daemon must be launched with --testnet flag", false}; const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; @@ -334,6 +335,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (m_daemon_address.empty()) m_daemon_address = std::string("http://") + m_daemon_host + ":" + std::to_string(m_daemon_port); + bool testnet = command_line::get_arg(vm, arg_testnet); + tools::password_container pwd_container; if (command_line::has_arg(vm, arg_password)) { @@ -378,12 +381,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } } - bool r = new_wallet(m_wallet_file, pwd_container.password(), m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic); + bool r = new_wallet(m_wallet_file, pwd_container.password(), m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, testnet); CHECK_AND_ASSERT_MES(r, false, "account creation failed"); } else { - bool r = open_wallet(m_wallet_file, pwd_container.password()); + bool r = open_wallet(m_wallet_file, pwd_container.password(), testnet); CHECK_AND_ASSERT_MES(r, false, "could not open account"); } @@ -423,11 +426,11 @@ bool simple_wallet::try_connect_to_daemon() } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key, bool recover, bool two_random) +bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key, bool recover, bool two_random, bool testnet) { m_wallet_file = wallet_file; - m_wallet.reset(new tools::wallet2()); + m_wallet.reset(new tools::wallet2(testnet)); m_wallet->callback(this); crypto::secret_key recovery_val; @@ -471,10 +474,10 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password) +bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password, bool testnet) { m_wallet_file = wallet_file; - m_wallet.reset(new tools::wallet2()); + m_wallet.reset(new tools::wallet2(testnet)); m_wallet->callback(this); try @@ -1075,6 +1078,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_restore_deterministic_wallet ); command_line::add_arg(desc_params, arg_non_deterministic ); command_line::add_arg(desc_params, arg_electrum_seed ); + command_line::add_arg(desc_params, arg_testnet); tools::wallet_rpc_server::init_options(desc_params); po::positional_options_description positional_options; @@ -1144,6 +1148,7 @@ int main(int argc, char* argv[]) return 1; } + bool testnet = command_line::get_arg(vm, arg_testnet); std::string wallet_file = command_line::get_arg(vm, arg_wallet_file); std::string wallet_password = command_line::get_arg(vm, arg_password); std::string daemon_address = command_line::get_arg(vm, arg_daemon_address); @@ -1156,7 +1161,7 @@ int main(int argc, char* argv[]) if (daemon_address.empty()) daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); - tools::wallet2 wal; + tools::wallet2 wal(testnet); try { LOG_PRINT_L0("Loading wallet..."); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 41197b4bb..17affd564 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -66,8 +66,8 @@ namespace cryptonote bool run_console_handler(); - bool new_wallet(const std::string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false); - bool open_wallet(const std::string &wallet_file, const std::string& password); + bool new_wallet(const std::string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false, bool testnet = false); + bool open_wallet(const std::string &wallet_file, const std::string& password, bool testnet); bool close_wallet(); bool viewkey(const std::vector &args = std::vector()); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 48aa164ab..be857c78a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -420,9 +420,6 @@ bool wallet2::clear() { m_blockchain.clear(); m_transfers.clear(); - cryptonote::block b; - cryptonote::generate_genesis_block(b); - m_blockchain.push_back(get_block_hash(b)); m_local_bc_height = 1; return true; } @@ -501,6 +498,10 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str()); if(!r) LOG_PRINT_RED_L0("String with address text not saved"); + cryptonote::block b; + generate_genesis(b); + m_blockchain.push_back(get_block_hash(b)); + store(); return retval; } @@ -573,15 +574,28 @@ void wallet2::load(const std::string& wallet_, const std::string& password) m_account_public_address.m_view_public_key != m_account.get_keys().m_account_address.m_view_public_key, error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); - if(m_blockchain.empty()) + cryptonote::block genesis; + generate_genesis(genesis); + crypto::hash genesis_hash = get_block_hash(genesis); + + if (m_blockchain.empty()) { - cryptonote::block b; - cryptonote::generate_genesis_block(b); - m_blockchain.push_back(get_block_hash(b)); + m_blockchain.push_back(genesis_hash); } + else + { + check_genesis(genesis_hash); + } + m_local_bc_height = m_blockchain.size(); } //---------------------------------------------------------------------------------------------------- +void wallet2::check_genesis(const crypto::hash& genesis_hash) { + std::string what("Genesis block missmatch. You probably use wallet without testnet flag with blockchain from test network or vice versa"); + + THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain[0], error::wallet_internal_error, what); +} +//---------------------------------------------------------------------------------------------------- void wallet2::store() { bool r = tools::serialize_obj_to_file(*this, m_wallet_file); @@ -918,4 +932,13 @@ std::vector wallet2::create_transactions(std::vector m_run; i_wallet2_callback* m_callback; + bool m_testnet; }; } BOOST_CLASS_VERSION(tools::wallet2, 7) diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp index 5f7bbc095..098b9878a 100644 --- a/tests/core_proxy/core_proxy.cpp +++ b/tests/core_proxy/core_proxy.cpp @@ -112,7 +112,7 @@ int main(int argc, char* argv[]) //initialize objects LOG_PRINT_L0("Initializing p2p server..."); - bool res = p2psrv.init(vm); + bool res = p2psrv.init(vm, false); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize p2p server."); LOG_PRINT_L0("P2p server initialized OK"); diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 685323127..d2990e009 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -487,7 +487,7 @@ inline bool do_replay_events(std::vector& events) cryptonote::cryptonote_protocol_stub pr; //TODO: stub only for this kind of test, make real validation of relayed objects cryptonote::core c(&pr); - if (!c.init(vm)) + if (!c.init(vm, false)) { std::cout << concolor::magenta << "Failed to init core" << concolor::normal << std::endl; return false;