diff --git a/create-hardfork/CMakeLists.txt b/create-hardfork/CMakeLists.txt new file mode 100644 index 00000000..41606829 --- /dev/null +++ b/create-hardfork/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) + +if (NOT OPENSSL_FOUND) + find_package(OpenSSL REQUIRED) +endif() + + +set(CREATE_HARDFORK_SOURCE + create-hardfork.cpp +) + +add_executable(create-hardfork ${CREATE_HARDFORK_SOURCE}) +target_link_libraries(create-hardfork overlay tdutils tdactor adnl tl_api dht + rldp catchain validatorsession full-node validator-hardfork ton_validator + validator-hardfork fift-lib memprof ${JEMALLOC_LIBRARIES}) + +install(TARGETS create-hardfork RUNTIME DESTINATION bin) diff --git a/create-hardfork/create-hardfork.cpp b/create-hardfork/create-hardfork.cpp new file mode 100644 index 00000000..1a6b7a8a --- /dev/null +++ b/create-hardfork/create-hardfork.cpp @@ -0,0 +1,333 @@ +/* + This file is part of TON Blockchain source code. + + TON Blockchain is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + TON Blockchain is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TON Blockchain. If not, see . + + In addition, as a special exception, the copyright holders give permission + to link the code of portions of this program with the OpenSSL library. + You must obey the GNU General Public License in all respects for all + of the code used other than OpenSSL. If you modify file(s) with this + exception, you may extend this exception to your version of the file(s), + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. If you delete this exception statement + from all source files in the program, then also delete it here. + + Copyright 2017-2020 Telegram Systems LLP +*/ +#include "adnl/adnl.h" +#include "adnl/utils.hpp" +#include "auto/tl/ton_api_json.h" +#include "dht/dht.h" +#include "overlay/overlays.h" +#include "td/utils/OptionsParser.h" +#include "td/utils/Time.h" +#include "td/utils/filesystem.h" +#include "td/utils/format.h" +#include "td/utils/Random.h" +#include "td/utils/port/signals.h" +#include "td/utils/port/FileFd.h" +#include "catchain/catchain.h" +#include "validator-session/validator-session.h" +#include "validator/manager-hardfork.h" +#include "td/utils/filesystem.h" +#include "td/utils/port/path.h" + +#include "validator/fabric.h" +#include "validator/impl/collator.h" +#include "crypto/vm/cp0.h" +#include "crypto/block/block-db.h" + +#include "common/errorlog.h" + +#if TD_DARWIN || TD_LINUX +#include +#endif +#include +#include + +int verbosity; + +struct IntError { + std::string err_msg; + IntError(std::string _msg) : err_msg(_msg) { + } + IntError(const char *_msg) : err_msg(_msg) { + } + IntError(td::Status _err) : err_msg(_err.to_string()) { + } + void show() const { + std::cerr << "fatal: " << err_msg << std::endl; + } +}; + +class HardforkCreator : public td::actor::Actor { + private: + td::actor::ActorOwn validator_manager_; + + std::string db_root_ = "/var/ton-work/db/"; + td::BufferSlice bs_; + std::vector ext_msgs_; + std::vector top_shard_descrs_; + bool need_save_file_{false}; + bool tdescr_save_{false}; + std::string tdescr_pfx_; + ton::BlockIdExt shard_top_block_id_; + + ton::ShardIdFull shard_{ton::masterchainId}; + + public: + void set_db_root(std::string db_root) { + db_root_ = db_root; + } + void set_shard(ton::ShardIdFull shard) { + LOG(DEBUG) << "setting shard to " << shard.to_str(); + shard_ = shard; + } + void set_shard_top_block(ton::BlockIdExt block_id) { + shard_top_block_id_ = block_id; + } + void set_top_descr_prefix(std::string tdescr_pfx) { + tdescr_pfx_ = tdescr_pfx; + tdescr_save_ = true; + } + void set_collator_flags(int flags) { + ton::collator_settings |= flags; + } + void start_up() override { + } + void alarm() override { + } + HardforkCreator() { + } + + void load_ext_message(std::string filename) { + try { + auto res1 = block::load_binary_file(filename); + if (res1.is_error()) { + throw IntError{res1.move_as_error()}; + } + ext_msgs_.emplace_back(res1.move_as_ok()); + } catch (IntError err) { + err.show(); + std::exit(7); + } + } + + void load_shard_block_message(std::string filename) { + try { + auto res1 = block::load_binary_file(filename); + if (res1.is_error()) { + throw IntError{res1.move_as_error()}; + } + top_shard_descrs_.emplace_back(res1.move_as_ok()); + } catch (IntError err) { + err.show(); + std::exit(7); + } + } + + void do_save_file() { + } + + void run() { + td::mkdir(db_root_).ensure(); + ton::errorlog::ErrorLog::create(db_root_); + if (!shard_.is_masterchain() && need_save_file_) { + td::mkdir(db_root_ + "/static").ensure(); + do_save_file(); + } + + auto opts = ton::validator::ValidatorManagerOptions::create( + ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, 0, ton::RootHash::zero(), ton::FileHash::zero()}, + ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, 0, ton::RootHash::zero(), ton::FileHash::zero()}); + opts.write().set_initial_sync_disabled(true); + validator_manager_ = + ton::validator::ValidatorManagerHardforkFactory::create(opts, shard_, shard_top_block_id_, db_root_); + for (auto &msg : ext_msgs_) { + td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManager::new_external_message, + std::move(msg)); + } + for (auto &topmsg : top_shard_descrs_) { + td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManager::new_shard_block, ton::BlockIdExt{}, + 0, std::move(topmsg)); + } + class Callback : public ton::validator::ValidatorManagerInterface::Callback { + private: + td::actor::ActorId id_; + bool tdescr_save_; + std::string tdescr_pfx_; + int tdescr_cnt_ = 0; + + public: + Callback(td::actor::ActorId id, bool tdescr_save = false, + std::string tdescr_pfx = "") + : id_(id), tdescr_save_(tdescr_save), tdescr_pfx_(tdescr_pfx) { + } + + void initial_read_complete(ton::validator::BlockHandle handle) override { + td::actor::send_closure(id_, &ton::validator::ValidatorManager::sync_complete, + td::PromiseCreator::lambda([](td::Unit) {})); + } + void add_shard(ton::ShardIdFull) override { + } + void del_shard(ton::ShardIdFull) override { + } + void send_ihr_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override { + } + void send_ext_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override { + } + void send_shard_block_info(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::BufferSlice data) override { + } + void send_broadcast(ton::BlockBroadcast broadcast) override { + } + void download_block(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout, + td::Promise promise) override { + } + void download_zero_state(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout, + td::Promise promise) override { + } + void download_persistent_state(ton::BlockIdExt block_id, ton::BlockIdExt masterchain_block_id, + td::uint32 priority, td::Timestamp timeout, + td::Promise promise) override { + } + void download_block_proof(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout, + td::Promise promise) override { + } + void download_block_proof_link(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout, + td::Promise promise) override { + } + void get_next_key_blocks(ton::BlockIdExt block_id, td::Timestamp timeout, + td::Promise> promise) override { + } + void download_archive(ton::BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout, + + td::Promise promise) override { + } + + void new_key_block(ton::validator::BlockHandle handle) override { + } + }; + + td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::install_callback, + std::make_unique(validator_manager_.get(), tdescr_save_, tdescr_pfx_), + td::PromiseCreator::lambda([](td::Unit) {})); + } +}; + +td::Result get_uint256(td::Slice str) { + TRY_RESULT(R, td::base64url_decode(str)); + if (R.length() != 32) { + return td::Status::Error("uint256 must have 64 bytes"); + } + td::Bits256 x; + as_slice(x).copy_from(td::Slice(R)); + return x; +} + +int parse_hex_digit(int c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + c |= 0x20; + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + return -1; +} + +int main(int argc, char *argv[]) { + SET_VERBOSITY_LEVEL(verbosity_INFO); + td::set_default_failure_signal_handler().ensure(); + + CHECK(vm::init_op_cp0()); + + td::actor::ActorOwn x; + + td::OptionsParser p; + p.set_description("test collate block"); + p.add_option('h', "help", "prints_help", [&]() { + char b[10240]; + td::StringBuilder sb(td::MutableSlice{b, 10000}); + sb << p; + std::cout << sb.as_cslice().c_str(); + std::exit(2); + return td::Status::OK(); + }); + p.add_option('D', "db", "root for dbs", [&](td::Slice fname) { + td::actor::send_closure(x, &HardforkCreator::set_db_root, fname.str()); + return td::Status::OK(); + }); + p.add_option('m', "ext-message", "binary file with serialized inbound external message", [&](td::Slice fname) { + td::actor::send_closure(x, &HardforkCreator::load_ext_message, fname.str()); + return td::Status::OK(); + }); + p.add_option('M', "top-shard-message", "binary file with serialized shard top block description", + [&](td::Slice fname) { + td::actor::send_closure(x, &HardforkCreator::load_shard_block_message, fname.str()); + return td::Status::OK(); + }); + p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) { + int v = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer(arg)); + SET_VERBOSITY_LEVEL(v); + return td::Status::OK(); + }); + p.add_option('w', "workchain", "[:]\tcollate block in this workchain", [&](td::Slice arg) { + ton::ShardId shard = 0; + auto pos = std::min(arg.find(':'), arg.size()); + TRY_RESULT(workchain, td::to_integer_safe(arg.substr(0, pos))); + int s = 60; + while (++pos < arg.size()) { + int x = parse_hex_digit(arg[pos]); + if (x < 0 || s < 0) { + return td::Status::Error("cannot parse hexadecimal shard id (prefix)"); + } + shard |= (ton::ShardId(x) << s); + s -= 4; + } + td::actor::send_closure(x, &HardforkCreator::set_shard, + ton::ShardIdFull{workchain, shard ? shard : ton::shardIdAll}); + return td::Status::OK(); + }); + p.add_option('T', "top-block", "BlockIdExt of top block (new block will be generated atop of it)", + [&](td::Slice arg) { + ton::BlockIdExt block_id; + if (block::parse_block_id_ext(arg, block_id)) { + LOG(INFO) << "setting previous block to " << block_id.to_str(); + td::actor::send_closure(x, &HardforkCreator::set_shard_top_block, block_id); + + return td::Status::OK(); + } else { + return td::Status::Error("cannot parse BlockIdExt"); + } + }); + p.add_option('d', "daemonize", "set SIGHUP", [&]() { + td::set_signal_handler(td::SignalType::HangUp, [](int sig) { +#if TD_DARWIN || TD_LINUX + close(0); + setsid(); +#endif + }).ensure(); + return td::Status::OK(); + }); + + td::actor::Scheduler scheduler({7}); + + scheduler.run_in_context([&] { x = td::actor::create_actor("testnode"); }); + + scheduler.run_in_context([&] { p.run(argc, argv).ensure(); }); + scheduler.run_in_context([&] { td::actor::send_closure(x, &HardforkCreator::run); }); + scheduler.run(); + + return 0; +}