1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +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

@ -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;