1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-14 12:12:21 +00:00

updated pow-miner + small bugfix

This commit is contained in:
ton 2020-07-10 13:46:16 +03:00
parent f064b1047a
commit dab7ee3f97
16 changed files with 344 additions and 25 deletions

View file

@ -307,8 +307,13 @@ if (WINGETOPT_FOUND)
target_link_libraries_system(tlbc wingetopt)
endif()
add_executable(pow-miner util/pow-miner.cpp util/Miner.cpp util/Miner.h)
target_link_libraries(pow-miner PUBLIC ton_crypto ton_block)
add_library(pow-miner-lib util/Miner.cpp util/Miner.h)
target_include_directories(pow-miner-lib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(pow-miner-lib PUBLIC ton_crypto ton_block)
add_executable(pow-miner util/pow-miner.cpp)
target_link_libraries(pow-miner PRIVATE ton_crypto ton_block pow-miner-lib)
if (WINGETOPT_FOUND)
target_link_libraries_system(fift wingetopt)
endif()

View file

@ -118,6 +118,10 @@ td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& ad
td::Ref<vm::Cell> res;
tlb::type_pack_cell(res, block::gen::t_Message_Any, message);
if (res.is_null()) {
/* body */ { message.body = vm::CellBuilder().store_ones(1).store_ref(std::move(body)).as_cellslice_ref(); }
tlb::type_pack_cell(res, block::gen::t_Message_Any, message);
}
CHECK(res.not_null());
return res;

View file

@ -1,3 +1,21 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Library 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#include "Miner.h"
#include "td/utils/Random.h"
@ -75,6 +93,9 @@ td::optional<std::string> Miner::run(const Options& options) {
td::int64 i = 0, i0 = 0;
for (; i < options.max_iterations; i++) {
if (!(i & 0xfffff) || head.back() != guard) {
if (options.token_) {
break;
}
if (options.hashes_computed) {
*options.hashes_computed += i - i0;
}

View file

@ -1,6 +1,25 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Library 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "block/block.h"
#include "td/utils/CancellationToken.h"
#include "td/utils/optional.h"
#include "td/utils/Time.h"
#include <atomic>
@ -16,6 +35,7 @@ class Miner {
td::optional<td::Timestamp> expire_at;
td::int64 max_iterations = std::numeric_limits<td::int64>::max();
std::atomic<td::uint64>* hashes_computed{nullptr};
td::CancellationToken token_;
};
static td::optional<std::string> run(const Options& options);

View file

@ -1,3 +1,30 @@
/*
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 <http://www.gnu.org/licenses/>.
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 "common/bigint.hpp"
#include "common/refint.h"
#include "block/block.h"

View file

@ -105,7 +105,7 @@ void TestNode::run() {
private:
td::actor::ActorId<TestNode> id_;
};
io_ = td::TerminalIO::create("> ", readline_enabled_, std::make_unique<Cb>(actor_id(this)));
io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique<Cb>(actor_id(this)));
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
if (remote_public_key_.empty()) {

View file

@ -323,7 +323,7 @@ class StorageCli : public td::actor::Actor {
td::actor::send_closure(actor_id(this), &StorageCli::parse_line, td::BufferSlice(options_.cmd.unwrap()));
} else {
ref_cnt_++;
io_ = td::TerminalIO::create("> ", options_.enable_readline, std::make_unique<Cb>(actor_shared(this)));
io_ = td::TerminalIO::create("> ", options_.enable_readline, false, std::make_unique<Cb>(actor_shared(this)));
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
}

View file

@ -112,7 +112,7 @@ TEST(Port, SparseFiles) {
unlink(path).ignore();
auto fd = FileFd::open(path, FileFd::Write | FileFd::CreateNew).move_as_ok();
ASSERT_EQ(0, fd.get_size().move_as_ok());
ASSERT_EQ(0, fd.get_real_size().move_as_ok());
// ASSERT_EQ(0, fd.get_real_size().move_as_ok());
int64 offset = 100000000;
fd.pwrite("a", offset).ensure();
ASSERT_EQ(offset + 1, fd.get_size().move_as_ok());

View file

@ -113,9 +113,11 @@ void TerminalIOImpl::start_up() {
}
#endif
td::actor::SchedulerContext::get()->get_poll().subscribe(stdin_.get_poll_info().extract_pollable_fd(this),
td::PollFlags::Read());
loop();
if (!no_input_) {
td::actor::SchedulerContext::get()->get_poll().subscribe(stdin_.get_poll_info().extract_pollable_fd(this),
td::PollFlags::Read());
loop();
}
}
void TerminalIOImpl::tear_down() {
@ -329,10 +331,10 @@ TerminalIOOutputter::~TerminalIOOutputter() {
}
}
td::actor::ActorOwn<TerminalIO> TerminalIO::create(std::string prompt, bool use_readline,
td::actor::ActorOwn<TerminalIO> TerminalIO::create(std::string prompt, bool use_readline, bool no_input,
std::unique_ptr<Callback> callback) {
return actor::create_actor<TerminalIOImpl>(actor::ActorOptions().with_name("terminal io").with_poll(), prompt,
use_readline, std::move(callback));
use_readline, no_input, std::move(callback));
}
TerminalIOImpl *TerminalIOImpl::instance_ = nullptr;

View file

@ -93,7 +93,7 @@ class TerminalIO : public actor::Actor {
virtual void set_log_interface() = 0;
virtual bool readline_used() const = 0;
static td::actor::ActorOwn<TerminalIO> create(std::string prompt, bool use_readline,
static td::actor::ActorOwn<TerminalIO> create(std::string prompt, bool use_readline, bool no_input,
std::unique_ptr<Callback> callback);
};

View file

@ -66,8 +66,8 @@ class TerminalIOImpl : public TerminalIO, td::ObserverBase {
void on_net() {
loop();
}
TerminalIOImpl(std::string prompt, bool use_readline, std::unique_ptr<Callback> callback)
: prompt_(prompt), use_readline_(use_readline), callback_(std::move(callback)) {
TerminalIOImpl(std::string prompt, bool use_readline, bool no_input, std::unique_ptr<Callback> callback)
: prompt_(prompt), use_readline_(use_readline), no_input_(no_input), callback_(std::move(callback)) {
}
int stdin_getc();
@ -83,6 +83,7 @@ class TerminalIOImpl : public TerminalIO, td::ObserverBase {
std::string prompt_;
bool use_readline_ = false;
bool no_input_ = false;
std::unique_ptr<Callback> callback_;
std::mutex out_mutex_;

View file

@ -69,7 +69,7 @@ if (TONLIB_ENABLE_JNI AND NOT ANDROID) # jni is available by default on Android
endif()
add_executable(tonlib-cli tonlib/tonlib-cli.cpp)
target_link_libraries(tonlib-cli tonlib tdactor tdutils terminal)
target_link_libraries(tonlib-cli tonlib tdactor tdutils terminal pow-miner-lib)
if (NOT CMAKE_CROSSCOMPILING)
if (TONLIB_ENABLE_JNI)

View file

@ -77,6 +77,16 @@ class TonlibClient : public td::actor::Actor {
std::string rwallet_init_public_key;
};
template <class T, class P>
void make_request(T&& request, P&& promise) {
td::Promise<typename std::decay_t<T>::ReturnType> new_promise = std::move(promise);
auto status = do_request(std::forward<T>(request), std::move(new_promise));
if (status.is_error()) {
new_promise.operator()(std::move(status));
}
}
private:
enum class State { Uninited, Running, Closed } state_ = State::Uninited;
td::unique_ptr<TonlibCallback> callback_;
@ -203,15 +213,6 @@ class TonlibClient : public td::actor::Actor {
void make_any_request(tonlib_api::Function& function, QueryContext query_context,
td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>&& promise);
template <class T, class P>
void make_request(T&& request, P&& promise) {
td::Promise<typename std::decay_t<T>::ReturnType> new_promise = std::move(promise);
auto status = do_request(std::forward<T>(request), std::move(new_promise));
if (status.is_error()) {
new_promise.operator()(std::move(status));
}
}
td::Result<FullConfig> validate_config(tonlib_api::object_ptr<tonlib_api::config> config);
void set_config(FullConfig config);

View file

@ -25,8 +25,14 @@
Copyright 2019-2020 Telegram Systems LLP
*/
#include "auto/tl/tonlib_api.h"
#include "block/block.h"
#include "common/bigint.hpp"
#include "common/refint.h"
#include "td/actor/actor.h"
#include "td/actor/common.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/OptionParser.h"
#include "td/utils/overloaded.h"
@ -48,6 +54,10 @@
#include "auto/tl/tonlib_api.hpp"
#include "crypto/util/Miner.h"
#include "vm/boc.h"
#include "vm/cells/CellBuilder.h"
#include <cinttypes>
#include <iostream>
#include <map>
@ -106,6 +116,9 @@ td::Result<Grams> parse_grams(td::Slice grams) {
return Grams{value};
}
// Temporary hack
td::actor::Scheduler* global_scheduler_{nullptr};
class TonlibCli : public td::actor::Actor {
public:
struct Options {
@ -153,6 +166,9 @@ class TonlibCli : public td::actor::Actor {
make_object<tonlib_api::key>(public_key, secret.copy()), td::SecureString(password))
: nullptr;
}
auto tonlib_api() const {
return make_object<tonlib_api::accountAddress>(address->account_address_);
}
};
std::map<std::uint64_t, td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>> query_handlers_;
@ -179,7 +195,7 @@ class TonlibCli : public td::actor::Actor {
};
if (!options_.one_shot) {
ref_cnt_++;
io_ = td::TerminalIO::create("> ", options_.enable_readline, std::make_unique<Cb>(actor_shared(this)));
io_ = td::TerminalIO::create("> ", options_.enable_readline, false, std::make_unique<Cb>(actor_shared(this)));
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
}
@ -317,6 +333,11 @@ class TonlibCli : public td::actor::Actor {
td::TerminalIO::out() << "rwallet address <key_id> <public_key>\n";
td::TerminalIO::out() << "rwallet init <key_id> <public_key> <start_at> [<seconds>:<value> ...]\n";
}
void pminer_help() {
td::TerminalIO::out() << "pminer help\n";
td::TerminalIO::out() << "pminer start <giver_addess> <my_address>\n";
td::TerminalIO::out() << "pminer stop\n";
}
void parse_line(td::BufferSlice line) {
if (is_closing_) {
@ -374,6 +395,7 @@ class TonlibCli : public td::actor::Actor {
dns_help();
pchan_help();
rwallet_help();
pminer_help();
td::TerminalIO::out()
<< "blockmode auto|manual\tWith auto mode, all queries will be executed with respect to the latest block. "
@ -477,6 +499,8 @@ class TonlibCli : public td::actor::Actor {
run_pchan_cmd(parser, std::move(cmd_promise));
} else if (cmd == "rwallet") {
run_rwallet_cmd(parser, std::move(cmd_promise));
} else if (cmd == "pminer") {
run_pminer_cmd(parser, std::move(cmd_promise));
} else if (cmd == "gethistory") {
get_history(parser.read_word(), std::move(cmd_promise));
} else if (cmd == "guessrevision") {
@ -556,6 +580,216 @@ class TonlibCli : public td::actor::Actor {
promise.set_error(td::Status::Error("Unknown command"));
}
class PowMiner : public td::actor::Actor {
public:
class Callback {
public:
};
struct Options {
Address giver_address;
Address my_address;
};
PowMiner(Options options, td::actor::ActorId<tonlib::TonlibClient> client)
: options_(std::move(options)), client_(std::move(client)) {
}
private:
Options options_;
td::actor::ActorId<tonlib::TonlibClient> client_;
td::optional<ton::Miner::Options> miner_options_;
static constexpr double QUERY_EACH = 5.0;
td::Timestamp next_options_query_at_;
bool need_run_miners_{false};
td::CancellationTokenSource source_;
ton::Miner::Options miner_options_copy_;
std::size_t threads_alive_{0};
std::vector<td::thread> threads_;
bool close_flag_{false};
template <class QueryT>
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
td::actor::send_lambda(client_,
[self = client_, query = std::move(query), promise = std::move(promise)]() mutable {
self.get_actor_unsafe().make_request(std::move(query), std::move(promise));
});
}
void start_up() override {
next_options_query_at_ = td::Timestamp::now();
loop();
}
void hangup() override {
close_flag_ = true;
source_.cancel();
try_stop();
}
void try_stop() {
if (threads_alive_ == 0) {
td::TerminalIO::out() << "pminer: stopped\n";
stop();
}
}
void loop() override {
if (close_flag_) {
try_stop();
return;
}
if (next_options_query_at_ && next_options_query_at_.is_in_past()) {
send_query(tonlib_api::smc_load(options_.giver_address.tonlib_api()),
promise_send_closure(td::actor::actor_id(this), &PowMiner::with_giver_state));
next_options_query_at_ = {};
}
if (miner_options_ && threads_.empty() && need_run_miners_) {
td::TerminalIO::out() << "pminer: start workers\n";
need_run_miners_ = false;
miner_options_copy_ = miner_options_.value();
miner_options_copy_.token_ = source_.get_cancellation_token();
auto n = td::thread::hardware_concurrency();
threads_alive_ = n;
for (td::uint32 i = 0; i < n; i++) {
threads_.emplace_back([this, actor_id = actor_id(this)] {
auto res = ton::Miner::run(miner_options_copy_);
global_scheduler_->run_in_context_external(
[&] { send_closure(actor_id, &PowMiner::got_answer, std::move(res)); });
});
}
}
alarm_timestamp().relax(next_options_query_at_);
}
void got_answer(td::optional<std::string> answer) {
source_.cancel();
if (--threads_alive_ == 0) {
threads_.clear();
}
if (answer) {
td::TerminalIO::out() << "pminer: got some result - sending query to the giver\n";
vm::CellBuilder cb;
cb.store_bytes(answer.unwrap());
send_query(tonlib_api::raw_createAndSendMessage(
options_.giver_address.tonlib_api(), "",
vm::std_boc_serialize(cb.finalize_novm()).move_as_ok().as_slice().str()),
promise_send_closure(td::actor::actor_id(this), &PowMiner::on_query_sent));
}
loop();
}
void on_query_sent(td::Result<tonlib_api::object_ptr<tonlib_api::ok>> r_ok) {
LOG_IF(ERROR, r_ok.is_error()) << "pminer: " << r_ok.error();
}
void with_giver_state(td::Result<tonlib_api::object_ptr<tonlib_api::smc_info>> r_info) {
if (r_info.is_error()) {
return with_giver_info(r_info.move_as_error());
}
send_query(tonlib_api::smc_runGetMethod(r_info.ok()->id_,
make_object<tonlib_api::smc_methodIdName>("get_pow_params"), {}),
promise_send_closure(td::actor::actor_id(this), &PowMiner::with_giver_info));
}
void with_giver_info(td::Result<tonlib_api::object_ptr<tonlib_api::smc_runResult>> r_info) {
auto status = do_with_giver_info(std::move(r_info));
LOG_IF(ERROR, status.is_error()) << "pminer: " << status;
next_options_query_at_ = td::Timestamp::in(QUERY_EACH);
return loop();
}
td::Result<td::RefInt256> to_number(const tonlib_api::object_ptr<tonlib_api::tvm_StackEntry>& entry,
td::int32 bits) {
if (entry->get_id() != tonlib_api::tvm_stackEntryNumber::ID) {
return td::Status::Error("Expected stackEntryNumber");
}
auto& number_str = static_cast<const tonlib_api::tvm_stackEntryNumber&>(*entry.get()).number_->number_;
auto num = td::make_refint();
if (num.write().parse_dec(number_str.data(), (int)number_str.size()) < (int)number_str.size()) {
return td::Status::Error("Failed to parse a number");
}
if (!num->unsigned_fits_bits(bits)) {
return td::Status::Error(PSLICE() << "Number is too big " << num->to_dec_string() << " " << bits);
}
return num;
}
td::Status do_with_giver_info(td::Result<tonlib_api::object_ptr<tonlib_api::smc_runResult>> r_info) {
TRY_RESULT(info, std::move(r_info));
if (info->stack_.size() < 2) {
return td::Status::Error("Unexpected `get_pow_params` result format");
}
TRY_RESULT(seed, to_number(info->stack_[0], 128));
TRY_RESULT(complexity, to_number(info->stack_[1], 256));
ton::Miner::Options options;
seed->export_bytes(options.seed.data(), 16, false);
complexity->export_bytes(options.complexity.data(), 32, false);
TRY_RESULT(address, block::StdAddress::parse(options_.my_address.address->account_address_));
options.my_address = std::move(address);
options.token_ = source_.get_cancellation_token();
if (miner_options_ && miner_options_.value().seed == options.seed) {
return td::Status::OK();
}
td::TerminalIO::out() << "pminer: got new options\n";
td::BigInt256 bigpower, hrate;
bigpower.set_pow2(256).mod_div(*complexity, hrate);
long long hash_rate = hrate.to_long();
td::TerminalIO::out() << "[ expected required hashes for success: " << hash_rate << " ]\n";
miner_options_ = std::move(options);
need_run_miners_ = true;
source_.cancel();
return td::Status::OK();
}
};
td::uint64 pow_miner_id_{0};
std::map<td::uint64, td::actor::ActorOwn<PowMiner>> pow_miners_;
void pminer_start(td::ConstParser& parser, td::Promise<td::Unit> promise) {
if (!pow_miners_.empty()) {
promise.set_error(td::Status::Error("One pminer is already running"));
}
TRY_RESULT_PROMISE_PREFIX(promise, giver_address, to_account_address(parser.read_word(), false), "giver address");
TRY_RESULT_PROMISE_PREFIX(promise, my_address, to_account_address(parser.read_word(), false), "my address");
auto id = ++pow_miner_id_;
PowMiner::Options options;
options.giver_address = std::move(giver_address);
options.my_address = std::move(my_address);
pow_miners_.emplace(id, td::actor::create_actor<PowMiner>("PowMiner", std::move(options), client_.get()));
td::TerminalIO::out() << "Miner #" << id << " created";
promise.set_value({});
}
void pminer_stop(td::ConstParser& parser, td::Promise<td::Unit> promise) {
pow_miners_.clear();
promise.set_value({});
}
void run_pminer_cmd(td::ConstParser& parser, td::Promise<td::Unit> promise) {
auto cmd = parser.read_word();
if (cmd == "help") {
pminer_help();
return promise.set_value(td::Unit());
}
if (cmd == "start") {
return pminer_start(parser, std::move(promise));
}
if (cmd == "stop") {
return pminer_stop(parser, std::move(promise));
}
promise.set_error(td::Status::Error("Unknown command"));
}
void run_pchan_cmd(td::ConstParser& parser, td::Promise<td::Unit> promise) {
auto cmd = parser.read_word();
if (cmd == "help") {
@ -2121,6 +2355,8 @@ int main(int argc, char* argv[]) {
}
td::actor::Scheduler scheduler({2});
// temporaty hack
global_scheduler_ = &scheduler;
scheduler.run_in_context([&] { td::actor::create_actor<TonlibCli>("console", options).release(); });
scheduler.run();
return 0;

View file

@ -92,7 +92,7 @@ void ValidatorEngineConsole::run() {
private:
td::actor::ActorId<ValidatorEngineConsole> id_;
};
io_ = td::TerminalIO::create("> ", readline_enabled_, std::make_unique<Cb>(actor_id(this)));
io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique<Cb>(actor_id(this)));
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
td::TerminalIO::out() << "connecting to " << remote_addr_ << "\n";

View file

@ -1958,6 +1958,7 @@ void ValidatorManagerImpl::add_handle_to_lru(BlockHandle handle) {
auto it = handle_lru_map_.find(handle->id());
if (it != handle_lru_map_.end()) {
CHECK(it->second->handle() == handle);
it->second->remove();
handle_lru_.put(it->second.get());
} else {
auto id = handle->id();
@ -1978,6 +1979,7 @@ void ValidatorManagerImpl::add_handle_to_lru(BlockHandle handle) {
BlockHandle ValidatorManagerImpl::get_handle_from_lru(BlockIdExt id) {
auto it = handle_lru_map_.find(id);
if (it != handle_lru_map_.end()) {
it->second->remove();
handle_lru_.put(it->second.get());
auto handle = it->second->handle();
CHECK(handle->id() == id);