mirror of
https://github.com/danog/ton.git
synced 2024-11-30 04:29:19 +01:00
13140ddf29
1. Updated block header, proofs now contain more data Notice, that old proofs may become invalid in the future 2. Fixed message routing 3. Fixed block creator id in block header 4. Support for full proofs in tonlib 5. Support for partial state download 6. Some other bugfixes
2885 lines
109 KiB
C++
2885 lines
109 KiB
C++
/*
|
|
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-2019 Telegram Systems LLP
|
|
*/
|
|
#include "validator-engine.hpp"
|
|
|
|
#include "ton/ton-types.h"
|
|
#include "ton/ton-tl.hpp"
|
|
|
|
#include "common/errorlog.h"
|
|
|
|
#include "crypto/vm/cp0.h"
|
|
#include "crypto/fift/utils.h"
|
|
|
|
#include "td/utils/filesystem.h"
|
|
#include "td/actor/MultiPromise.h"
|
|
#include "td/utils/overloaded.h"
|
|
#include "td/utils/OptionsParser.h"
|
|
#include "td/utils/port/path.h"
|
|
#include "td/utils/port/signals.h"
|
|
#include "td/utils/port/user.h"
|
|
#include "td/utils/ThreadSafeCounter.h"
|
|
#include "td/utils/TsFileLog.h"
|
|
#include "td/utils/Random.h"
|
|
|
|
#include "auto/tl/lite_api.h"
|
|
|
|
#include "memprof/memprof.h"
|
|
|
|
#include "dht/dht.hpp"
|
|
|
|
#if TD_DARWIN || TD_LINUX
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <cstdlib>
|
|
#include <set>
|
|
|
|
Config::Config() {
|
|
out_port = 3278;
|
|
full_node = ton::PublicKeyHash::zero();
|
|
}
|
|
|
|
Config::Config(ton::ton_api::engine_validator_config &config) {
|
|
full_node = ton::PublicKeyHash::zero();
|
|
out_port = static_cast<td::uint16>(config.out_port_);
|
|
if (!out_port) {
|
|
out_port = 3278;
|
|
}
|
|
for (auto &addr : config.addrs_) {
|
|
td::IPAddress in_ip;
|
|
td::IPAddress out_ip;
|
|
std::shared_ptr<ton::adnl::AdnlProxy> proxy = nullptr;
|
|
std::vector<AdnlCategory> categories;
|
|
std::vector<AdnlCategory> priority_categories;
|
|
ton::ton_api::downcast_call(
|
|
*addr.get(),
|
|
td::overloaded(
|
|
[&](const ton::ton_api::engine_addr &obj) {
|
|
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast<td::uint16>(obj.port_)).ensure();
|
|
out_ip = in_ip;
|
|
categories = obj.categories_;
|
|
priority_categories = obj.priority_categories_;
|
|
},
|
|
[&](const ton::ton_api::engine_addrProxy &obj) {
|
|
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.in_ip_), static_cast<td::uint16>(obj.in_port_))
|
|
.ensure();
|
|
out_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.out_ip_), static_cast<td::uint16>(obj.out_port_))
|
|
.ensure();
|
|
if (obj.proxy_type_) {
|
|
auto R = ton::adnl::AdnlProxy::create(*obj.proxy_type_.get());
|
|
R.ensure();
|
|
proxy = R.move_as_ok();
|
|
categories = obj.categories_;
|
|
priority_categories = obj.priority_categories_;
|
|
}
|
|
}));
|
|
|
|
config_add_network_addr(in_ip, out_ip, std::move(proxy), categories, priority_categories).ensure();
|
|
}
|
|
for (auto &adnl : config.adnl_) {
|
|
config_add_adnl_addr(ton::PublicKeyHash{adnl->id_}, adnl->category_).ensure();
|
|
}
|
|
for (auto &dht : config.dht_) {
|
|
config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure();
|
|
}
|
|
for (auto &val : config.validators_) {
|
|
auto key = ton::PublicKeyHash{val->id_};
|
|
config_add_validator_permanent_key(key, val->election_date_, val->expire_at_).ensure();
|
|
for (auto &temp : val->temp_keys_) {
|
|
config_add_validator_temp_key(key, ton::PublicKeyHash{temp->key_}, temp->expire_at_).ensure();
|
|
}
|
|
for (auto &adnl : val->adnl_addrs_) {
|
|
config_add_validator_adnl_id(key, ton::PublicKeyHash{adnl->id_}, adnl->expire_at_).ensure();
|
|
}
|
|
}
|
|
config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure();
|
|
|
|
for (auto &serv : config.liteservers_) {
|
|
config_add_lite_server(ton::PublicKeyHash{serv->id_}, serv->port_).ensure();
|
|
}
|
|
|
|
for (auto &serv : config.control_) {
|
|
auto key = ton::PublicKeyHash{serv->id_};
|
|
config_add_control_interface(key, serv->port_).ensure();
|
|
|
|
for (auto &proc : serv->allowed_) {
|
|
config_add_control_process(key, serv->port_, ton::PublicKeyHash{proc->id_}, proc->permissions_).ensure();
|
|
}
|
|
}
|
|
|
|
if (config.gc_) {
|
|
for (auto &gc : config.gc_->ids_) {
|
|
config_add_gc(ton::PublicKeyHash{gc}).ensure();
|
|
}
|
|
}
|
|
}
|
|
|
|
ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_Addr>> addrs_vec;
|
|
for (auto &x : addrs) {
|
|
if (x.second.proxy) {
|
|
addrs_vec.push_back(ton::create_tl_object<ton::ton_api::engine_addrProxy>(
|
|
static_cast<td::int32>(x.second.in_addr.get_ipv4()), x.second.in_addr.get_port(),
|
|
static_cast<td::int32>(x.first.addr.get_ipv4()), x.first.addr.get_port(), x.second.proxy->tl(),
|
|
std::vector<td::int32>(x.second.cats.begin(), x.second.cats.end()),
|
|
std::vector<td::int32>(x.second.priority_cats.begin(), x.second.priority_cats.end())));
|
|
} else {
|
|
addrs_vec.push_back(ton::create_tl_object<ton::ton_api::engine_addr>(
|
|
static_cast<td::int32>(x.first.addr.get_ipv4()), x.first.addr.get_port(),
|
|
std::vector<td::int32>(x.second.cats.begin(), x.second.cats.end()),
|
|
std::vector<td::int32>(x.second.priority_cats.begin(), x.second.priority_cats.end())));
|
|
}
|
|
}
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_adnl>> adnl_vec;
|
|
for (auto &x : adnl_ids) {
|
|
adnl_vec.push_back(ton::create_tl_object<ton::ton_api::engine_adnl>(x.first.tl(), x.second));
|
|
}
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_dht>> dht_vec;
|
|
for (auto &x : dht_ids) {
|
|
dht_vec.push_back(ton::create_tl_object<ton::ton_api::engine_dht>(x.tl()));
|
|
}
|
|
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator>> val_vec;
|
|
for (auto &val : validators) {
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validatorTempKey>> temp_vec;
|
|
for (auto &t : val.second.temp_keys) {
|
|
temp_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validatorTempKey>(t.first.tl(), t.second));
|
|
}
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validatorAdnlAddress>> adnl_val_vec;
|
|
for (auto &t : val.second.adnl_ids) {
|
|
adnl_val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validatorAdnlAddress>(t.first.tl(), t.second));
|
|
}
|
|
val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator>(
|
|
val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at));
|
|
}
|
|
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_liteServer>> liteserver_vec;
|
|
for (auto &x : liteservers) {
|
|
liteserver_vec.push_back(ton::create_tl_object<ton::ton_api::engine_liteServer>(x.second.tl(), x.first));
|
|
}
|
|
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_controlInterface>> control_vec;
|
|
for (auto &x : controls) {
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_controlProcess>> control_proc_vec;
|
|
for (auto &y : x.second.clients) {
|
|
control_proc_vec.push_back(ton::create_tl_object<ton::ton_api::engine_controlProcess>(y.first.tl(), y.second));
|
|
}
|
|
control_vec.push_back(ton::create_tl_object<ton::ton_api::engine_controlInterface>(x.second.key.tl(), x.first,
|
|
std::move(control_proc_vec)));
|
|
}
|
|
|
|
auto gc_vec = ton::create_tl_object<ton::ton_api::engine_gc>(std::vector<td::Bits256>{});
|
|
for (auto &id : gc) {
|
|
gc_vec->ids_.push_back(id.tl());
|
|
}
|
|
return ton::create_tl_object<ton::ton_api::engine_validator_config>(
|
|
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), full_node.tl(),
|
|
std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
|
|
std::shared_ptr<ton::adnl::AdnlProxy> proxy,
|
|
std::vector<AdnlCategory> cats, std::vector<AdnlCategory> prio_cats) {
|
|
Addr addr{out_ip};
|
|
|
|
auto it = addrs.find(addr);
|
|
if (it != addrs.end()) {
|
|
bool mod = false;
|
|
if (!(it->second.in_addr == in_ip)) {
|
|
it->second.in_addr = in_ip;
|
|
mod = true;
|
|
}
|
|
if (it->second.proxy != proxy) {
|
|
it->second.proxy = std::move(proxy);
|
|
mod = true;
|
|
}
|
|
for (auto &c : cats) {
|
|
if (it->second.cats.insert(c).second) {
|
|
mod = true;
|
|
}
|
|
}
|
|
for (auto &c : prio_cats) {
|
|
if (it->second.priority_cats.insert(c).second) {
|
|
mod = true;
|
|
}
|
|
}
|
|
return mod;
|
|
} else {
|
|
it = addrs.emplace(std::move(addr), AddrCats{}).first;
|
|
it->second.in_addr = in_ip;
|
|
it->second.proxy = std::move(proxy);
|
|
for (auto &c : cats) {
|
|
it->second.cats.insert(c);
|
|
}
|
|
for (auto &c : prio_cats) {
|
|
it->second.priority_cats.insert(c);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_adnl_addr(ton::PublicKeyHash addr, AdnlCategory cat) {
|
|
auto it = adnl_ids.find(addr);
|
|
if (it != adnl_ids.end()) {
|
|
if (it->second != cat) {
|
|
it->second = cat;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
incref(addr);
|
|
adnl_ids.emplace(addr, cat);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_dht_node(ton::PublicKeyHash id) {
|
|
if (dht_ids.count(id) > 0) {
|
|
return false;
|
|
}
|
|
if (adnl_ids.count(id) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "to-be-added dht node not in adnl nodes list");
|
|
}
|
|
incref(id);
|
|
dht_ids.insert(id);
|
|
return true;
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_validator_permanent_key(ton::PublicKeyHash id, ton::UnixTime election_date,
|
|
ton::UnixTime expire_at) {
|
|
for (auto &x : validators) {
|
|
if (x.second.election_date == election_date && x.first != id) {
|
|
return td::Status::Error(ton::ErrorCode::protoviolation, "duplicate election date");
|
|
}
|
|
}
|
|
auto it = validators.find(id);
|
|
if (it != validators.end()) {
|
|
if (it->second.election_date != election_date) {
|
|
return td::Status::Error(ton::ErrorCode::protoviolation, "election date changed");
|
|
}
|
|
if (it->second.expire_at != expire_at) {
|
|
it->second.expire_at = expire_at;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
incref(id);
|
|
validators[id] = Validator{{}, {}, election_date, expire_at};
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_validator_temp_key(ton::PublicKeyHash perm_key, ton::PublicKeyHash id,
|
|
ton::UnixTime expire_at) {
|
|
if (validators.count(perm_key) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "unknown permanent validator key");
|
|
}
|
|
auto &v = validators[perm_key];
|
|
|
|
auto it = v.temp_keys.find(id);
|
|
if (it != v.temp_keys.end()) {
|
|
if (it->second != expire_at) {
|
|
it->second = expire_at;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
incref(id);
|
|
v.temp_keys.emplace(id, expire_at);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id,
|
|
ton::UnixTime expire_at) {
|
|
if (adnl_ids.count(adnl_id) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "to-be-added validator adnl address not in adnl nodes list");
|
|
}
|
|
if (validators.count(perm_key) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "unknown permanent validator key");
|
|
}
|
|
auto &v = validators[perm_key];
|
|
|
|
auto it = v.adnl_ids.find(adnl_id);
|
|
if (it != v.adnl_ids.end()) {
|
|
if (it->second != expire_at) {
|
|
it->second = expire_at;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
incref(adnl_id);
|
|
v.adnl_ids.emplace(adnl_id, expire_at);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_full_node_adnl_id(ton::PublicKeyHash id) {
|
|
if (full_node == id) {
|
|
return false;
|
|
}
|
|
if (adnl_ids.count(id) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "to-be-added full node adnl address not in adnl nodes list");
|
|
}
|
|
if (!full_node.is_zero()) {
|
|
decref(full_node);
|
|
}
|
|
if (!id.is_zero()) {
|
|
incref(id);
|
|
}
|
|
full_node = id;
|
|
return true;
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_lite_server(ton::PublicKeyHash key, td::int32 port) {
|
|
if (controls.count(port) > 0) {
|
|
return td::Status::Error(ton::ErrorCode::error, "duplicate port");
|
|
}
|
|
auto it = liteservers.find(port);
|
|
if (it != liteservers.end()) {
|
|
if (it->second == key) {
|
|
return false;
|
|
} else {
|
|
return td::Status::Error(ton::ErrorCode::error, "duplicate port");
|
|
}
|
|
} else {
|
|
incref(key);
|
|
liteservers.emplace(port, key);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_control_interface(ton::PublicKeyHash key, td::int32 port) {
|
|
if (liteservers.count(port) > 0) {
|
|
return td::Status::Error(ton::ErrorCode::error, "duplicate port");
|
|
}
|
|
auto it = controls.find(port);
|
|
if (it != controls.end()) {
|
|
if (it->second.key == key) {
|
|
return false;
|
|
} else {
|
|
return td::Status::Error(ton::ErrorCode::error, "duplicate port");
|
|
}
|
|
} else {
|
|
incref(key);
|
|
controls.emplace(port, Control{key, {}});
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_control_process(ton::PublicKeyHash key, td::int32 port, ton::PublicKeyHash id,
|
|
td::uint32 permissions) {
|
|
if (controls.count(port) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::error, "unknown control interface");
|
|
}
|
|
auto &v = controls[port];
|
|
if (v.key != key) {
|
|
return td::Status::Error(ton::ErrorCode::error, "unknown control interface");
|
|
}
|
|
|
|
auto it = v.clients.find(id);
|
|
if (it != v.clients.end()) {
|
|
if (!permissions) {
|
|
v.clients.erase(id);
|
|
return true;
|
|
}
|
|
if (it->second != permissions) {
|
|
it->second = permissions;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
if (!permissions) {
|
|
return false;
|
|
}
|
|
v.clients.emplace(id, permissions);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_add_gc(ton::PublicKeyHash key) {
|
|
return gc.insert(key).second;
|
|
}
|
|
|
|
void Config::decref(ton::PublicKeyHash key) {
|
|
auto v = keys_refcnt[key]--;
|
|
CHECK(v > 0);
|
|
if (v == 1) {
|
|
config_add_gc(key).ensure();
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_network_addr(td::IPAddress a, std::vector<AdnlCategory> cats,
|
|
std::vector<AdnlCategory> prio_cats) {
|
|
Addr addr{a};
|
|
|
|
auto it = addrs.find(addr);
|
|
if (it != addrs.end()) {
|
|
bool mod = false;
|
|
for (auto &c : cats) {
|
|
if (it->second.cats.erase(c)) {
|
|
mod = true;
|
|
}
|
|
}
|
|
for (auto &c : prio_cats) {
|
|
if (it->second.priority_cats.erase(c)) {
|
|
mod = true;
|
|
}
|
|
}
|
|
if (it->second.cats.size() == 0 && it->second.priority_cats.size() == 0) {
|
|
addrs.erase(it);
|
|
}
|
|
return mod;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_adnl_addr(ton::PublicKeyHash addr) {
|
|
if (adnl_ids.count(addr) == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (dht_ids.count(addr)) {
|
|
return td::Status::Error(ton::ErrorCode::error, "adnl addr still in use");
|
|
}
|
|
if (full_node == addr) {
|
|
return td::Status::Error(ton::ErrorCode::error, "adnl addr still in use");
|
|
}
|
|
|
|
for (auto &x : validators) {
|
|
if (x.second.adnl_ids.count(addr)) {
|
|
return td::Status::Error(ton::ErrorCode::error, "adnl addr still in use");
|
|
}
|
|
}
|
|
|
|
decref(addr);
|
|
adnl_ids.erase(addr);
|
|
return true;
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_dht_node(ton::PublicKeyHash id) {
|
|
if (dht_ids.count(id) == 0) {
|
|
return false;
|
|
}
|
|
decref(id);
|
|
dht_ids.erase(id);
|
|
return true;
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_validator_permanent_key(ton::PublicKeyHash id) {
|
|
if (validators.count(id) == 0) {
|
|
return false;
|
|
}
|
|
auto &v = validators[id];
|
|
for (auto &temp_key : v.temp_keys) {
|
|
decref(temp_key.first);
|
|
}
|
|
for (auto &adnl_id : v.adnl_ids) {
|
|
decref(adnl_id.first);
|
|
}
|
|
decref(id);
|
|
validators.erase(id);
|
|
return true;
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_validator_temp_key(ton::PublicKeyHash perm_key, ton::PublicKeyHash id) {
|
|
if (validators.count(perm_key) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "unknown permanent validator key");
|
|
}
|
|
auto &v = validators[perm_key];
|
|
|
|
auto it = v.temp_keys.find(id);
|
|
if (it != v.temp_keys.end()) {
|
|
decref(id);
|
|
v.temp_keys.erase(id);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id) {
|
|
if (validators.count(perm_key) == 0) {
|
|
return td::Status::Error(ton::ErrorCode::notready, "unknown permanent validator key");
|
|
}
|
|
auto &v = validators[perm_key];
|
|
|
|
auto it = v.adnl_ids.find(adnl_id);
|
|
if (it != v.temp_keys.end()) {
|
|
decref(adnl_id);
|
|
v.adnl_ids.erase(adnl_id);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_full_node_adnl_id() {
|
|
return config_add_full_node_adnl_id(ton::PublicKeyHash::zero());
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_lite_server(td::int32 port) {
|
|
auto it = liteservers.find(port);
|
|
if (it != liteservers.end()) {
|
|
decref(it->second);
|
|
liteservers.erase(it);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_control_interface(td::int32 port) {
|
|
auto it = controls.find(port);
|
|
if (it != controls.end()) {
|
|
decref(it->second.key);
|
|
controls.erase(it);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_control_process(td::int32 port, ton::PublicKeyHash id) {
|
|
auto it = controls.find(port);
|
|
if (it != controls.end()) {
|
|
return it->second.clients.erase(id);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
td::Result<bool> Config::config_del_gc(ton::PublicKeyHash key) {
|
|
return gc.erase(key);
|
|
}
|
|
|
|
class ValidatorElectionBidCreator : public td::actor::Actor {
|
|
public:
|
|
ValidatorElectionBidCreator(td::uint32 date, std::string addr, std::string wallet, std::string dir,
|
|
td::actor::ActorId<ValidatorEngine> engine,
|
|
td::actor::ActorId<ton::keyring::Keyring> keyring, td::Promise<td::BufferSlice> promise)
|
|
: date_(date)
|
|
, addr_(addr)
|
|
, wallet_(wallet)
|
|
, dir_(dir)
|
|
, engine_(engine)
|
|
, keyring_(keyring)
|
|
, promise_(std::move(promise)) {
|
|
ttl_ = date_ + 7 * 86400;
|
|
}
|
|
|
|
void start_up() override {
|
|
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
perm_key_full_ = pk1.compute_public_key();
|
|
perm_key_ = perm_key_full_.compute_short_id();
|
|
|
|
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
adnl_key_full_ = ton::adnl::AdnlNodeIdFull{pk2.compute_public_key()};
|
|
adnl_addr_ = adnl_key_full_.compute_short_id();
|
|
|
|
td::MultiPromise mp;
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
|
if (R.is_error()) {
|
|
td::actor::send_closure(SelfId, &ValidatorElectionBidCreator::abort_query,
|
|
R.move_as_error_prefix("keyring fail: "));
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorElectionBidCreator::written_keys);
|
|
}
|
|
});
|
|
auto ig = mp.init_guard();
|
|
ig.add_promise(std::move(P));
|
|
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk1), false, ig.get_promise());
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk2), false, ig.get_promise());
|
|
}
|
|
|
|
void written_keys() {
|
|
td::MultiPromise mp;
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
|
if (R.is_error()) {
|
|
td::actor::send_closure(SelfId, &ValidatorElectionBidCreator::abort_query,
|
|
R.move_as_error_prefix("update config fail: "));
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorElectionBidCreator::updated_config);
|
|
}
|
|
});
|
|
auto ig = mp.init_guard();
|
|
ig.add_promise(std::move(P));
|
|
|
|
td::actor::send_closure(engine_, &ValidatorEngine::add_key_to_set, perm_key_full_);
|
|
td::actor::send_closure(engine_, &ValidatorEngine::add_key_to_set, adnl_key_full_.pubkey());
|
|
td::actor::send_closure(engine_, &ValidatorEngine::try_add_validator_permanent_key, perm_key_, date_, ttl_,
|
|
ig.get_promise());
|
|
td::actor::send_closure(engine_, &ValidatorEngine::try_add_validator_temp_key, perm_key_, perm_key_, ttl_,
|
|
ig.get_promise());
|
|
td::actor::send_closure(engine_, &ValidatorEngine::try_add_adnl_node, adnl_addr_.pubkey_hash(), cat_,
|
|
ig.get_promise());
|
|
td::actor::send_closure(engine_, &ValidatorEngine::try_add_validator_adnl_addr, perm_key_, adnl_addr_.pubkey_hash(),
|
|
ttl_, ig.get_promise());
|
|
}
|
|
|
|
void updated_config() {
|
|
auto codeR = td::read_file_str(dir_ + "/validator-elect-req.fif");
|
|
if (codeR.is_error()) {
|
|
abort_query(codeR.move_as_error_prefix("fif not found (validator-elect-req.fif)"));
|
|
return;
|
|
}
|
|
auto R = fift::mem_run_fift(codeR.move_as_ok(),
|
|
{"validator-elect-req.fif", wallet_, td::to_string(date_), td::to_string(frac),
|
|
adnl_addr_.bits256_value().to_hex(), "OUTPUT"},
|
|
dir_ + "/");
|
|
if (R.is_error()) {
|
|
abort_query(R.move_as_error_prefix("fift fail (validator-elect-req.fif)"));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
|
if (R.is_error()) {
|
|
td::actor::send_closure(SelfId, &ValidatorElectionBidCreator::abort_query,
|
|
R.move_as_error_prefix("sign fail: "));
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorElectionBidCreator::signed_bid, R.move_as_ok());
|
|
}
|
|
});
|
|
|
|
auto res = R.move_as_ok();
|
|
auto to_signR = res.source_lookup.read_file("OUTPUT");
|
|
if (to_signR.is_error()) {
|
|
abort_query(td::Status::Error(PSTRING() << "strange error: no to sign file. Output: " << res.output));
|
|
return;
|
|
}
|
|
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_message, perm_key_,
|
|
td::BufferSlice{to_signR.move_as_ok().data}, std::move(P));
|
|
}
|
|
|
|
void signed_bid(td::BufferSlice signature) {
|
|
signature_ = std::move(signature);
|
|
|
|
auto codeR = td::read_file_str(dir_ + "/validator-elect-signed.fif");
|
|
if (codeR.is_error()) {
|
|
abort_query(codeR.move_as_error_prefix("fif not found (validator-elect-req.fif)"));
|
|
return;
|
|
}
|
|
auto R = fift::mem_run_fift(
|
|
codeR.move_as_ok(),
|
|
{"validator-elect-signed.fif", wallet_, td::to_string(date_), td::to_string(frac),
|
|
adnl_addr_.bits256_value().to_hex(), td::base64_encode(perm_key_full_.export_as_slice().as_slice()),
|
|
td::base64_encode(signature_.as_slice()), "OUTPUT"},
|
|
dir_ + "/");
|
|
if (R.is_error()) {
|
|
abort_query(R.move_as_error_prefix("fift fail (validator-elect-req.fif)"));
|
|
return;
|
|
}
|
|
|
|
auto res = R.move_as_ok();
|
|
auto dataR = res.source_lookup.read_file("OUTPUT");
|
|
if (dataR.is_error()) {
|
|
abort_query(td::Status::Error("strage error: no result boc"));
|
|
return;
|
|
}
|
|
|
|
result_ = td::BufferSlice(dataR.move_as_ok().data);
|
|
finish_query();
|
|
}
|
|
|
|
void abort_query(td::Status error) {
|
|
promise_.set_value(ValidatorEngine::create_control_query_error(std::move(error)));
|
|
stop();
|
|
}
|
|
void finish_query() {
|
|
promise_.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_electionBid>(
|
|
date_, perm_key_.tl(), adnl_addr_.bits256_value(), std::move(result_)));
|
|
stop();
|
|
}
|
|
|
|
private:
|
|
td::uint32 date_;
|
|
std::string addr_;
|
|
std::string wallet_;
|
|
std::string dir_;
|
|
td::actor::ActorId<ValidatorEngine> engine_;
|
|
td::actor::ActorId<ton::keyring::Keyring> keyring_;
|
|
|
|
td::Promise<td::BufferSlice> promise_;
|
|
|
|
td::uint32 ttl_;
|
|
AdnlCategory cat_ = 2;
|
|
double frac = 2.7;
|
|
|
|
ton::PublicKeyHash perm_key_;
|
|
ton::PublicKey perm_key_full_;
|
|
ton::adnl::AdnlNodeIdShort adnl_addr_;
|
|
ton::adnl::AdnlNodeIdFull adnl_key_full_;
|
|
|
|
td::BufferSlice signature_;
|
|
td::BufferSlice result_;
|
|
};
|
|
|
|
class CheckDhtServerStatusQuery : public td::actor::Actor {
|
|
public:
|
|
void start_up() override {
|
|
auto &n = dht_config_->nodes();
|
|
|
|
result_.resize(n.size(), false);
|
|
|
|
pending_ = n.size();
|
|
for (td::uint32 i = 0; i < n.size(); i++) {
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), idx = i](td::Result<td::BufferSlice> R) {
|
|
td::actor::send_closure(SelfId, &CheckDhtServerStatusQuery::got_result, idx, R.is_ok());
|
|
});
|
|
|
|
auto &E = n.list().at(i);
|
|
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_peer, local_id_, E.adnl_id(), E.addr_list());
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::send_query, local_id_, E.adnl_id().compute_short_id(), "ping",
|
|
std::move(P), td::Timestamp::in(1.0),
|
|
ton::create_serialize_tl_object<ton::ton_api::dht_getSignedAddressList>());
|
|
}
|
|
}
|
|
|
|
void got_result(td::uint32 idx, bool result) {
|
|
result_[idx] = result;
|
|
CHECK(pending_ > 0);
|
|
if (!--pending_) {
|
|
finish_query();
|
|
}
|
|
}
|
|
|
|
void finish_query() {
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_dhtServerStatus>> vec;
|
|
auto &n = dht_config_->nodes();
|
|
for (td::uint32 i = 0; i < n.size(); i++) {
|
|
auto &E = n.list().at(i);
|
|
vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator_dhtServerStatus>(
|
|
E.adnl_id().compute_short_id().bits256_value(), result_[i] ? 1 : 0));
|
|
}
|
|
promise_.set_value(
|
|
ton::create_serialize_tl_object<ton::ton_api::engine_validator_dhtServersStatus>(std::move(vec)));
|
|
stop();
|
|
}
|
|
|
|
CheckDhtServerStatusQuery(std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config, ton::adnl::AdnlNodeIdShort local_id,
|
|
td::actor::ActorId<ton::adnl::Adnl> adnl, td::Promise<td::BufferSlice> promise)
|
|
: dht_config_(std::move(dht_config)), local_id_(local_id), adnl_(adnl), promise_(std::move(promise)) {
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config_;
|
|
|
|
std::vector<bool> result_;
|
|
td::uint32 pending_;
|
|
|
|
ton::adnl::AdnlNodeIdShort local_id_;
|
|
td::actor::ActorId<ton::adnl::Adnl> adnl_;
|
|
td::Promise<td::BufferSlice> promise_;
|
|
};
|
|
|
|
void ValidatorEngine::set_local_config(std::string str) {
|
|
local_config_ = str;
|
|
}
|
|
void ValidatorEngine::set_global_config(std::string str) {
|
|
global_config_ = str;
|
|
}
|
|
void ValidatorEngine::set_db_root(std::string db_root) {
|
|
db_root_ = db_root;
|
|
}
|
|
void ValidatorEngine::start_up() {
|
|
alarm_timestamp() = td::Timestamp::in(1.0 + td::Random::fast(0, 100) * 0.01);
|
|
}
|
|
|
|
void ValidatorEngine::alarm() {
|
|
alarm_timestamp() = td::Timestamp::in(1.0 + td::Random::fast(0, 100) * 0.01);
|
|
|
|
if (started_) {
|
|
if (!validator_manager_.empty()) {
|
|
auto P = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this)](td::Result<td::Ref<ton::validator::MasterchainState>> R) {
|
|
if (R.is_ok()) {
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::got_state, R.move_as_ok());
|
|
}
|
|
});
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::get_top_masterchain_state,
|
|
std::move(P));
|
|
}
|
|
if (state_.not_null()) {
|
|
bool need_write = false;
|
|
|
|
auto val_set = state_->get_total_validator_set(0);
|
|
auto e = val_set->export_vector();
|
|
std::set<ton::PublicKeyHash> adnl_ids;
|
|
for (auto &el : e) {
|
|
adnl_ids.insert(ton::PublicKeyHash{el.addr});
|
|
}
|
|
std::set<ton::PublicKeyHash> to_del;
|
|
for (auto &val : config_.validators) {
|
|
if (val.second.expire_at < state_->get_unix_time() &&
|
|
!val_set->is_validator(ton::NodeIdShort{val.first.bits256_value()})) {
|
|
to_del.insert(val.first);
|
|
} else {
|
|
std::set<ton::PublicKeyHash> to_del_2;
|
|
for (auto &x : val.second.adnl_ids) {
|
|
if (x.second < state_->get_unix_time() && !adnl_ids.count(x.first)) {
|
|
to_del_2.insert(x.first);
|
|
}
|
|
}
|
|
for (auto &x : to_del_2) {
|
|
config_.config_del_validator_temp_key(val.first, x);
|
|
need_write = true;
|
|
}
|
|
}
|
|
}
|
|
for (auto &x : to_del) {
|
|
config_.config_del_validator_permanent_key(x);
|
|
if (!validator_manager_.empty()) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::del_permanent_key, x,
|
|
[](td::Unit) {});
|
|
}
|
|
if (!full_node_.empty()) {
|
|
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::del_permanent_key, x,
|
|
[](td::Unit) {});
|
|
}
|
|
need_write = true;
|
|
}
|
|
|
|
if (need_write) {
|
|
write_config([](td::Unit) {});
|
|
}
|
|
}
|
|
for (auto &x : config_.gc) {
|
|
if (running_gc_.count(x) == 0) {
|
|
running_gc_.insert(x);
|
|
keys_.erase(x);
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), x](td::Result<td::Unit> R) {
|
|
R.ensure();
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::deleted_key, x);
|
|
});
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::del_key, x, std::move(P));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ValidatorEngine::deleted_key(ton::PublicKeyHash x) {
|
|
CHECK(running_gc_.count(x) == 1);
|
|
running_gc_.erase(x);
|
|
auto R = config_.config_del_gc(x);
|
|
R.ensure();
|
|
if (R.move_as_ok()) {
|
|
write_config([](td::Unit) {});
|
|
}
|
|
}
|
|
|
|
td::Status ValidatorEngine::load_global_config() {
|
|
TRY_RESULT_PREFIX(conf_data, td::read_file(global_config_), "failed to read: ");
|
|
TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: ");
|
|
|
|
ton::ton_api::config_global conf;
|
|
TRY_STATUS_PREFIX(ton::ton_api::from_json(conf, conf_json.get_object()), "json does not fit TL scheme: ");
|
|
|
|
// TODO
|
|
// add adnl static nodes
|
|
if (conf.adnl_) {
|
|
if (conf.adnl_->static_nodes_) {
|
|
TRY_RESULT_PREFIX_ASSIGN(adnl_static_nodes_, ton::adnl::AdnlNodesList::create(conf.adnl_->static_nodes_),
|
|
"bad static adnl nodes: ");
|
|
}
|
|
}
|
|
if (!conf.dht_) {
|
|
return td::Status::Error(ton::ErrorCode::error, "does not contain [dht] section");
|
|
}
|
|
|
|
TRY_RESULT_PREFIX(dht, ton::dht::Dht::create_global_config(std::move(conf.dht_)), "bad [dht] section: ");
|
|
dht_config_ = std::move(dht);
|
|
|
|
if (!conf.validator_) {
|
|
return td::Status::Error(ton::ErrorCode::error, "does not contain [validator] section");
|
|
}
|
|
|
|
if (!conf.validator_->zero_state_) {
|
|
return td::Status::Error(ton::ErrorCode::error, "[validator] section does not contain [zero_state]");
|
|
}
|
|
|
|
auto zero_state = ton::create_block_id(conf.validator_->zero_state_);
|
|
if (zero_state.id.workchain != ton::masterchainId || zero_state.id.shard != ton::shardIdAll ||
|
|
zero_state.id.seqno != 0) {
|
|
return td::Status::Error(ton::ErrorCode::error, "[validator] section contains invalid [zero_state]");
|
|
}
|
|
if (zero_state.root_hash.is_zero() || zero_state.file_hash.is_zero()) {
|
|
return td::Status::Error(ton::ErrorCode::error, "[validator] section contains incomplete [zero_state]");
|
|
}
|
|
|
|
ton::BlockIdExt init_block;
|
|
if (!conf.validator_->init_block_) {
|
|
init_block = zero_state;
|
|
} else {
|
|
init_block = ton::create_block_id(conf.validator_->init_block_);
|
|
if (init_block.id.workchain != ton::masterchainId || init_block.id.shard != ton::shardIdAll) {
|
|
return td::Status::Error(ton::ErrorCode::error, "[validator] section contains invalid [init_block]");
|
|
}
|
|
if (init_block.root_hash.is_zero() || init_block.file_hash.is_zero()) {
|
|
return td::Status::Error(ton::ErrorCode::error, "[validator] section contains incomplete [init_block]");
|
|
}
|
|
}
|
|
|
|
validator_options_ = ton::validator::ValidatorManagerOptions::create(zero_state, init_block);
|
|
if (state_ttl_ != 0) {
|
|
validator_options_.write().set_state_ttl(state_ttl_);
|
|
}
|
|
if (block_ttl_ != 0) {
|
|
validator_options_.write().set_block_ttl(block_ttl_);
|
|
}
|
|
if (sync_ttl_ != 0) {
|
|
validator_options_.write().set_sync_blocks_before(sync_ttl_);
|
|
}
|
|
if (archive_ttl_ != 0) {
|
|
validator_options_.write().set_archive_ttl(archive_ttl_);
|
|
}
|
|
if (key_proof_ttl_ != 0) {
|
|
validator_options_.write().set_key_proof_ttl(key_proof_ttl_);
|
|
}
|
|
if (db_depth_ <= 32) {
|
|
validator_options_.write().set_filedb_depth(db_depth_);
|
|
}
|
|
|
|
std::vector<ton::BlockIdExt> h;
|
|
for (auto &x : conf.validator_->hardforks_) {
|
|
auto b = ton::create_block_id(x);
|
|
if (!b.is_masterchain()) {
|
|
return td::Status::Error(ton::ErrorCode::error,
|
|
"[validator/hardforks] section contains not masterchain block id");
|
|
}
|
|
if (!b.is_valid_full()) {
|
|
return td::Status::Error(ton::ErrorCode::error, "[validator/hardforks] section contains invalid block_id");
|
|
}
|
|
for (auto &y : h) {
|
|
if (y.is_valid() && y.seqno() >= b.seqno()) {
|
|
y.invalidate();
|
|
}
|
|
}
|
|
h.push_back(b);
|
|
}
|
|
validator_options_.write().set_hardforks(std::move(h));
|
|
|
|
return td::Status::OK();
|
|
}
|
|
|
|
void ValidatorEngine::load_empty_local_config(td::Promise<td::Unit> promise) {
|
|
auto ret_promise = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::write_config, std::move(promise));
|
|
}
|
|
});
|
|
|
|
td::MultiPromise mp;
|
|
auto ig = mp.init_guard();
|
|
ig.add_promise(std::move(ret_promise));
|
|
|
|
for (auto &addr : addrs_) {
|
|
config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int32>{0, 1, 2, 3}, std::vector<td::int32>{})
|
|
.ensure();
|
|
}
|
|
|
|
{
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
auto id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, ig.get_promise());
|
|
config_.config_add_adnl_addr(id, 0).ensure();
|
|
config_.config_add_dht_node(id).ensure();
|
|
}
|
|
|
|
{
|
|
auto adnl_pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
keys_.emplace(adnl_pk.compute_short_id(), adnl_pk.compute_public_key());
|
|
auto adnl_short_id = adnl_pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(adnl_pk), false, ig.get_promise());
|
|
config_.config_add_adnl_addr(adnl_short_id, 1).ensure();
|
|
config_.config_add_full_node_adnl_id(adnl_short_id).ensure();
|
|
}
|
|
}
|
|
|
|
void ValidatorEngine::load_local_config(td::Promise<td::Unit> promise) {
|
|
if (local_config_.size() == 0) {
|
|
load_empty_local_config(std::move(promise));
|
|
return;
|
|
}
|
|
auto conf_data_R = td::read_file(local_config_);
|
|
if (conf_data_R.is_error()) {
|
|
promise.set_error(conf_data_R.move_as_error_prefix("failed to read: "));
|
|
return;
|
|
}
|
|
auto conf_data = conf_data_R.move_as_ok();
|
|
auto conf_json_R = td::json_decode(conf_data.as_slice());
|
|
if (conf_json_R.is_error()) {
|
|
promise.set_error(conf_data_R.move_as_error_prefix("failed to parse json: "));
|
|
return;
|
|
}
|
|
auto conf_json = conf_json_R.move_as_ok();
|
|
|
|
ton::ton_api::config_local conf;
|
|
auto S = ton::ton_api::from_json(conf, conf_json.get_object());
|
|
if (S.is_error()) {
|
|
promise.set_error(S.move_as_error_prefix("json does not fit TL scheme"));
|
|
return;
|
|
}
|
|
|
|
auto ret_promise = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::write_config, std::move(promise));
|
|
}
|
|
});
|
|
|
|
td::MultiPromise mp;
|
|
auto ig = mp.init_guard();
|
|
ig.add_promise(std::move(ret_promise));
|
|
|
|
for (auto &addr : addrs_) {
|
|
config_.config_add_network_addr(addr, addr, nullptr, std::vector<td::int32>{0, 1, 2, 3}, std::vector<td::int32>{})
|
|
.ensure();
|
|
}
|
|
|
|
for (auto &local_id : conf.local_ids_) {
|
|
ton::PrivateKey pk{local_id->id_};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, ig.get_promise());
|
|
}
|
|
|
|
td::uint32 max_time = 2000000000;
|
|
|
|
if (conf.dht_.size() > 0) {
|
|
for (auto &d : conf.dht_) {
|
|
ton::ton_api::downcast_call(*d.get(), td::overloaded(
|
|
[&](ton::ton_api::dht_config_local &obj) {
|
|
auto node_id = ton::adnl::AdnlNodeIdShort{obj.id_->id_};
|
|
auto it = keys_.find(node_id.pubkey_hash());
|
|
if (it == keys_.end()) {
|
|
ig.get_promise().set_error(td::Status::Error(
|
|
ton::ErrorCode::error, "cannot find private key for dht"));
|
|
return;
|
|
}
|
|
|
|
config_.config_add_adnl_addr(node_id.pubkey_hash(), 0).ensure();
|
|
config_.config_add_dht_node(node_id.pubkey_hash()).ensure();
|
|
},
|
|
[&](ton::ton_api::dht_config_random_local &obj) {
|
|
for (td::int32 i = 0; i < obj.cnt_; i++) {
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
auto id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key,
|
|
std::move(pk), false, ig.get_promise());
|
|
config_.config_add_adnl_addr(id, 0).ensure();
|
|
config_.config_add_dht_node(id).ensure();
|
|
}
|
|
}));
|
|
}
|
|
} else {
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
auto id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, ig.get_promise());
|
|
config_.config_add_adnl_addr(id, 0).ensure();
|
|
config_.config_add_dht_node(id).ensure();
|
|
}
|
|
|
|
if (conf.validators_.size() > 0) {
|
|
for (auto &val : conf.validators_) {
|
|
ton::ton_api::downcast_call(
|
|
*val.get(), td::overloaded(
|
|
[&](ton::ton_api::validator_config_local &obj) {
|
|
auto id = ton::PublicKeyHash{obj.id_->id_};
|
|
auto it = keys_.find(id);
|
|
if (it == keys_.end()) {
|
|
ig.get_promise().set_error(
|
|
td::Status::Error(ton::ErrorCode::error, "cannot find private key for dht"));
|
|
return;
|
|
}
|
|
|
|
config_.config_add_adnl_addr(id, 2).ensure();
|
|
config_.config_add_validator_permanent_key(id, 0, max_time).ensure();
|
|
config_.config_add_validator_temp_key(id, id, max_time).ensure();
|
|
config_.config_add_validator_adnl_id(id, id, max_time).ensure();
|
|
},
|
|
[&](ton::ton_api::validator_config_random_local &obj) {
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
auto id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false,
|
|
ig.get_promise());
|
|
|
|
config_.config_add_adnl_addr(id, 2).ensure();
|
|
config_.config_add_validator_permanent_key(id, 0, max_time).ensure();
|
|
config_.config_add_validator_temp_key(id, id, max_time).ensure();
|
|
config_.config_add_validator_adnl_id(id, id, max_time).ensure();
|
|
}));
|
|
}
|
|
} else {
|
|
// DO NOTHING
|
|
}
|
|
|
|
{
|
|
auto adnl_pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
keys_.emplace(adnl_pk.compute_short_id(), adnl_pk.compute_public_key());
|
|
auto adnl_short_id = adnl_pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(adnl_pk), false, ig.get_promise());
|
|
config_.config_add_adnl_addr(adnl_short_id, 1).ensure();
|
|
config_.config_add_full_node_adnl_id(adnl_short_id).ensure();
|
|
}
|
|
|
|
for (auto &ls : conf.liteservers_) {
|
|
ton::ton_api::downcast_call(*ls.get(), td::overloaded(
|
|
[&](ton::ton_api::liteserver_config_local &cfg) {
|
|
ton::PrivateKey pk{cfg.id_};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
auto short_id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key,
|
|
std::move(pk), false, ig.get_promise());
|
|
config_.config_add_lite_server(short_id, cfg.port_).ensure();
|
|
},
|
|
[&](ton::ton_api::liteserver_config_random_local &cfg) {
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
auto short_id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key,
|
|
std::move(pk), false, ig.get_promise());
|
|
config_.config_add_lite_server(short_id, cfg.port_).ensure();
|
|
}));
|
|
}
|
|
|
|
for (auto &ci : conf.control_) {
|
|
ton::PrivateKey pk{ci->priv_};
|
|
keys_.emplace(pk.compute_short_id(), pk.compute_public_key());
|
|
auto short_id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, ig.get_promise());
|
|
|
|
config_.config_add_control_interface(short_id, ci->port_).ensure();
|
|
config_.config_add_control_process(short_id, ci->port_, ton::PublicKeyHash{ci->pub_}, 0x7fffffff).ensure();
|
|
}
|
|
}
|
|
|
|
void ValidatorEngine::load_config(td::Promise<td::Unit> promise) {
|
|
if (!config_file_.size()) {
|
|
config_file_ = db_root_ + "/config.json";
|
|
}
|
|
auto conf_data_R = td::read_file(config_file_);
|
|
if (conf_data_R.is_error()) {
|
|
auto P = td::PromiseCreator::lambda(
|
|
[name = local_config_, new_name = config_file_, promise = std::move(promise)](td::Result<td::Unit> R) {
|
|
if (R.is_error()) {
|
|
LOG(ERROR) << "failed to parse local config '" << name << "': " << R.move_as_error();
|
|
std::_Exit(2);
|
|
} else {
|
|
LOG(ERROR) << "created config file '" << new_name << "'";
|
|
LOG(ERROR) << "check it manually before continue";
|
|
std::_Exit(0);
|
|
}
|
|
});
|
|
|
|
load_local_config(std::move(P));
|
|
return;
|
|
}
|
|
|
|
auto conf_data = conf_data_R.move_as_ok();
|
|
auto conf_json_R = td::json_decode(conf_data.as_slice());
|
|
if (conf_json_R.is_error()) {
|
|
promise.set_error(conf_json_R.move_as_error_prefix("failed to parse json: "));
|
|
return;
|
|
}
|
|
auto conf_json = conf_json_R.move_as_ok();
|
|
|
|
ton::ton_api::engine_validator_config conf;
|
|
auto S = ton::ton_api::from_json(conf, conf_json.get_object());
|
|
if (S.is_error()) {
|
|
promise.set_error(S.move_as_error_prefix("json does not fit TL scheme"));
|
|
return;
|
|
}
|
|
|
|
config_ = Config{conf};
|
|
|
|
td::MultiPromise mp;
|
|
auto ig = mp.init_guard();
|
|
ig.add_promise(std::move(promise));
|
|
|
|
for (auto &key : config_.keys_refcnt) {
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key_short, key.first, get_key_promise(ig));
|
|
}
|
|
|
|
write_config(ig.get_promise());
|
|
}
|
|
|
|
void ValidatorEngine::write_config(td::Promise<td::Unit> promise) {
|
|
auto s = td::json_encode<std::string>(td::ToJson(*config_.tl().get()), true);
|
|
|
|
auto S = td::write_file(config_file_, s);
|
|
if (S.is_ok()) {
|
|
promise.set_value(td::Unit());
|
|
} else {
|
|
promise.set_error(std::move(S));
|
|
}
|
|
}
|
|
|
|
td::Promise<ton::PublicKey> ValidatorEngine::get_key_promise(td::MultiPromise::InitGuard &ig) {
|
|
auto P = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this), promise = ig.get_promise()](td::Result<ton::PublicKey> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::got_key, R.move_as_ok());
|
|
promise.set_value(td::Unit());
|
|
}
|
|
});
|
|
return std::move(P);
|
|
}
|
|
|
|
void ValidatorEngine::got_key(ton::PublicKey key) {
|
|
keys_[key.compute_short_id()] = key;
|
|
}
|
|
|
|
void ValidatorEngine::start() {
|
|
read_config_ = true;
|
|
start_adnl();
|
|
}
|
|
|
|
void ValidatorEngine::start_adnl() {
|
|
adnl_network_manager_ = ton::adnl::AdnlNetworkManager::create(config_.out_port);
|
|
adnl_ = ton::adnl::Adnl::create(db_root_, keyring_.get());
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_network_manager, adnl_network_manager_.get());
|
|
|
|
for (auto &addr : config_.addrs) {
|
|
add_addr(addr.first, addr.second);
|
|
}
|
|
for (auto &adnl : config_.adnl_ids) {
|
|
add_adnl(adnl.first, adnl.second);
|
|
}
|
|
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config, std::move(adnl_static_nodes_));
|
|
started_adnl();
|
|
}
|
|
|
|
void ValidatorEngine::add_addr(const Config::Addr &addr, const Config::AddrCats &cats) {
|
|
if (!cats.proxy) {
|
|
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_self_addr, addr.addr,
|
|
cats.cats.size() ? 0 : 1);
|
|
} else {
|
|
td::actor::send_closure(adnl_network_manager_, &ton::adnl::AdnlNetworkManager::add_proxy_addr, addr.addr,
|
|
cats.proxy, cats.cats.size() ? 0 : 1);
|
|
}
|
|
|
|
td::uint32 ts = static_cast<td::uint32>(td::Clocks::system());
|
|
|
|
for (auto cat : cats.cats) {
|
|
CHECK(cat >= 0);
|
|
ton::adnl::AdnlAddress x = ton::adnl::AdnlAddressImpl::create(
|
|
ton::create_tl_object<ton::ton_api::adnl_address_udp>(cats.in_addr.get_ipv4(), cats.in_addr.get_port()));
|
|
addr_lists_[cat].add_addr(std::move(x));
|
|
addr_lists_[cat].set_version(ts);
|
|
addr_lists_[cat].set_reinit_date(ton::adnl::Adnl::adnl_start_time());
|
|
}
|
|
for (auto cat : cats.priority_cats) {
|
|
CHECK(cat >= 0);
|
|
ton::adnl::AdnlAddress x = ton::adnl::AdnlAddressImpl::create(
|
|
ton::create_tl_object<ton::ton_api::adnl_address_udp>(cats.in_addr.get_ipv4(), cats.in_addr.get_port()));
|
|
prio_addr_lists_[cat].add_addr(std::move(x));
|
|
prio_addr_lists_[cat].set_version(ts);
|
|
prio_addr_lists_[cat].set_reinit_date(ton::adnl::Adnl::adnl_start_time());
|
|
}
|
|
}
|
|
|
|
void ValidatorEngine::add_adnl(ton::PublicKeyHash id, AdnlCategory cat) {
|
|
CHECK(keys_.count(id) > 0);
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]}, addr_lists_[cat]);
|
|
}
|
|
|
|
void ValidatorEngine::started_adnl() {
|
|
start_dht();
|
|
}
|
|
|
|
void ValidatorEngine::add_dht(ton::PublicKeyHash id) {
|
|
auto D = ton::dht::Dht::create(ton::adnl::AdnlNodeIdShort{id}, db_root_, dht_config_, keyring_.get(), adnl_.get());
|
|
D.ensure();
|
|
|
|
dht_nodes_[id] = D.move_as_ok();
|
|
if (default_dht_node_.is_zero()) {
|
|
default_dht_node_ = id;
|
|
}
|
|
}
|
|
|
|
void ValidatorEngine::start_dht() {
|
|
for (auto &dht : config_.dht_ids) {
|
|
add_dht(dht);
|
|
}
|
|
|
|
CHECK(!default_dht_node_.is_zero());
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[default_dht_node_].get());
|
|
|
|
started_dht();
|
|
}
|
|
|
|
void ValidatorEngine::started_dht() {
|
|
start_rldp();
|
|
}
|
|
|
|
void ValidatorEngine::start_rldp() {
|
|
rldp_ = ton::rldp::Rldp::create(adnl_.get());
|
|
started_rldp();
|
|
}
|
|
|
|
void ValidatorEngine::started_rldp() {
|
|
start_overlays();
|
|
}
|
|
|
|
void ValidatorEngine::start_overlays() {
|
|
overlay_manager_ =
|
|
ton::overlay::Overlays::create(db_root_, keyring_.get(), adnl_.get(), dht_nodes_[default_dht_node_].get());
|
|
started_overlays();
|
|
}
|
|
|
|
void ValidatorEngine::started_overlays() {
|
|
start_validator();
|
|
}
|
|
|
|
void ValidatorEngine::start_validator() {
|
|
validator_options_.write().set_allow_blockchain_init(config_.validators.size() > 0);
|
|
validator_manager_ = ton::validator::ValidatorManagerFactory::create(
|
|
validator_options_, db_root_, keyring_.get(), adnl_.get(), rldp_.get(), overlay_manager_.get());
|
|
|
|
for (auto &v : config_.validators) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_permanent_key, v.first,
|
|
[](td::Unit) {});
|
|
|
|
for (auto &t : v.second.temp_keys) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_temp_key, t.first,
|
|
[](td::Unit) {});
|
|
}
|
|
}
|
|
|
|
started_validator();
|
|
}
|
|
|
|
void ValidatorEngine::started_validator() {
|
|
start_full_node();
|
|
}
|
|
|
|
void ValidatorEngine::start_full_node() {
|
|
if (!config_.full_node.is_zero()) {
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
auto short_id = pk.compute_short_id();
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
|
|
full_node_ = ton::validator::fullnode::FullNode::create(
|
|
short_id, ton::adnl::AdnlNodeIdShort{config_.full_node}, validator_options_->zero_block_id().file_hash,
|
|
keyring_.get(), adnl_.get(), rldp_.get(), dht_nodes_[default_dht_node_].get(), overlay_manager_.get(),
|
|
validator_manager_.get(), db_root_);
|
|
}
|
|
|
|
for (auto &v : config_.validators) {
|
|
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_permanent_key, v.first,
|
|
[](td::Unit) {});
|
|
}
|
|
|
|
started_full_node();
|
|
}
|
|
|
|
void ValidatorEngine::started_full_node() {
|
|
start_lite_server();
|
|
}
|
|
|
|
void ValidatorEngine::add_lite_server(ton::PublicKeyHash id, td::uint16 port) {
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]},
|
|
ton::adnl::AdnlAddressList{});
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_id,
|
|
ton::adnl::AdnlNodeIdShort{id});
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_ext_server_port, port);
|
|
}
|
|
|
|
void ValidatorEngine::start_lite_server() {
|
|
for (auto &s : config_.liteservers) {
|
|
add_lite_server(s.second, static_cast<td::uint16>(s.first));
|
|
}
|
|
|
|
started_lite_server();
|
|
}
|
|
|
|
void ValidatorEngine::started_lite_server() {
|
|
start_control_interface();
|
|
}
|
|
|
|
void ValidatorEngine::add_control_interface(ton::PublicKeyHash id, td::uint16 port) {
|
|
class Callback : public ton::adnl::Adnl::Callback {
|
|
public:
|
|
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
|
|
td::BufferSlice data) override {
|
|
}
|
|
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
|
td::Promise<td::BufferSlice> promise) override {
|
|
td::actor::send_closure(id_, &ValidatorEngine::process_control_query, port_, src, dst, std::move(data),
|
|
std::move(promise));
|
|
}
|
|
|
|
Callback(td::actor::ActorId<ValidatorEngine> id, td::uint16 port) : id_(id), port_(port) {
|
|
}
|
|
|
|
private:
|
|
td::actor::ActorId<ValidatorEngine> id_;
|
|
td::uint16 port_;
|
|
};
|
|
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{keys_[id]},
|
|
ton::adnl::AdnlAddressList{});
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{id}, std::string(""),
|
|
std::make_unique<Callback>(actor_id(this), port));
|
|
td::actor::send_closure(control_ext_server_, &ton::adnl::AdnlExtServer::add_local_id, ton::adnl::AdnlNodeIdShort{id});
|
|
td::actor::send_closure(control_ext_server_, &ton::adnl::AdnlExtServer::add_tcp_port, port);
|
|
}
|
|
|
|
void ValidatorEngine::add_control_process(ton::PublicKeyHash id, td::uint16 port, ton::PublicKeyHash pub,
|
|
td::int32 permissions) {
|
|
control_permissions_[CI_key{id, port, pub}] |= permissions;
|
|
}
|
|
|
|
void ValidatorEngine::start_control_interface() {
|
|
std::vector<ton::adnl::AdnlNodeIdShort> c_ids;
|
|
|
|
std::vector<td::uint16> ports;
|
|
auto P = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this)](td::Result<td::actor::ActorOwn<ton::adnl::AdnlExtServer>> R) {
|
|
R.ensure();
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::started_control_interface, R.move_as_ok());
|
|
});
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::create_ext_server, std::move(c_ids), std::move(ports), std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::started_control_interface(td::actor::ActorOwn<ton::adnl::AdnlExtServer> control_ext_server) {
|
|
control_ext_server_ = std::move(control_ext_server);
|
|
for (auto &s : config_.controls) {
|
|
add_control_interface(s.second.key, static_cast<td::uint16>(s.first));
|
|
|
|
for (auto &p : s.second.clients) {
|
|
add_control_process(s.second.key, static_cast<td::uint16>(s.first), p.first, p.second);
|
|
}
|
|
}
|
|
started();
|
|
}
|
|
|
|
void ValidatorEngine::started() {
|
|
started_ = true;
|
|
}
|
|
|
|
void ValidatorEngine::try_add_adnl_node(ton::PublicKeyHash key, AdnlCategory cat, td::Promise<td::Unit> promise) {
|
|
if (cat < 0 || static_cast<td::uint32>(cat) > max_cat()) {
|
|
promise.set_error(td::Status::Error(ton::ErrorCode::protoviolation, "bad category value"));
|
|
return;
|
|
}
|
|
|
|
auto R = config_.config_add_adnl_addr(key, cat);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
add_adnl(key, cat);
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_dht_node(ton::PublicKeyHash key_hash, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_dht_node(key_hash);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
add_dht(key_hash);
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_validator_permanent_key(ton::PublicKeyHash key_hash, td::uint32 election_date,
|
|
td::uint32 ttl, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_validator_permanent_key(key_hash, election_date, ttl);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
td::MultiPromise mp;
|
|
auto ig = mp.init_guard();
|
|
ig.add_promise(std::move(promise));
|
|
|
|
if (!validator_manager_.empty()) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_permanent_key, key_hash,
|
|
ig.get_promise());
|
|
}
|
|
if (!full_node_.empty()) {
|
|
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_permanent_key, key_hash,
|
|
ig.get_promise());
|
|
}
|
|
|
|
write_config(ig.get_promise());
|
|
}
|
|
|
|
void ValidatorEngine::try_add_validator_temp_key(ton::PublicKeyHash perm_key, ton::PublicKeyHash temp_key,
|
|
td::uint32 ttl, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_validator_temp_key(perm_key, temp_key, ttl);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
if (!validator_manager_.empty()) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_temp_key, temp_key,
|
|
std::move(promise));
|
|
}
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_validator_adnl_addr(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id,
|
|
td::uint32 ttl, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_validator_adnl_id(perm_key, adnl_id, ttl);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_full_node_adnl_addr(ton::PublicKeyHash id, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_full_node_adnl_id(id);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
if (!full_node_.empty()) {
|
|
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::update_adnl_id,
|
|
ton::adnl::AdnlNodeIdShort{id}, [](td::Unit) {});
|
|
}
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_liteserver(ton::PublicKeyHash id, td::int32 port, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_lite_server(id, port);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
add_lite_server(id, static_cast<td::uint16>(port));
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_control_interface(ton::PublicKeyHash id, td::int32 port, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_control_interface(id, port);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
add_control_interface(id, static_cast<td::uint16>(port));
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_control_process(ton::PublicKeyHash id, td::int32 port, ton::PublicKeyHash pub,
|
|
td::int32 permissions, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_add_control_process(id, port, pub, permissions);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
add_control_process(id, static_cast<td::uint16>(port), pub, permissions);
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_adnl_node(ton::PublicKeyHash pub, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_del_adnl_addr(pub);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::del_id, ton::adnl::AdnlNodeIdShort{pub}, [](td::Unit) {});
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_dht_node(ton::PublicKeyHash pub, td::Promise<td::Unit> promise) {
|
|
if (dht_nodes_.size() == 1 && pub == default_dht_node_) {
|
|
promise.set_error(td::Status::Error(ton::ErrorCode::error, "cannot remove last dht node"));
|
|
return;
|
|
}
|
|
auto R = config_.config_del_dht_node(pub);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
if (pub == default_dht_node_) {
|
|
default_dht_node_ = *config_.dht_ids.begin();
|
|
auto d = dht_nodes_[default_dht_node_].get();
|
|
CHECK(!d.empty());
|
|
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, d);
|
|
td::actor::send_closure(overlay_manager_, &ton::overlay::Overlays::update_dht_node, d);
|
|
if (!full_node_.empty()) {
|
|
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::update_dht_node, d);
|
|
}
|
|
}
|
|
dht_nodes_.erase(pub);
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_validator_permanent_key(ton::PublicKeyHash pub, td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_del_validator_permanent_key(pub);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
if (!validator_manager_.empty()) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::del_permanent_key, pub,
|
|
[](td::Unit) {});
|
|
}
|
|
if (!full_node_.empty()) {
|
|
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::del_permanent_key, pub, [](td::Unit) {});
|
|
}
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_validator_temp_key(ton::PublicKeyHash perm, ton::PublicKeyHash temp_key,
|
|
td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_del_validator_temp_key(perm, temp_key);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
if (!validator_manager_.empty()) {
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::del_temp_key, temp_key,
|
|
[](td::Unit) {});
|
|
}
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_validator_adnl_addr(ton::PublicKeyHash perm, ton::PublicKeyHash adnl_id,
|
|
td::Promise<td::Unit> promise) {
|
|
auto R = config_.config_del_validator_adnl_id(perm, adnl_id);
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::reload_adnl_addrs() {
|
|
addr_lists_.clear();
|
|
prio_addr_lists_.clear();
|
|
for (auto &addr : config_.addrs) {
|
|
add_addr(addr.first, addr.second);
|
|
}
|
|
for (auto &adnl : config_.adnl_ids) {
|
|
add_adnl(adnl.first, adnl.second);
|
|
}
|
|
}
|
|
|
|
void ValidatorEngine::try_add_listening_port(td::uint32 ip, td::int32 port, std::vector<AdnlCategory> cats,
|
|
std::vector<AdnlCategory> prio_cats, td::Promise<td::Unit> promise) {
|
|
td::IPAddress a;
|
|
a.init_ipv4_port(td::IPAddress::ipv4_to_str(ip), static_cast<td::uint16>(port)).ensure();
|
|
auto R = config_.config_add_network_addr(a, a, nullptr, std::move(cats), std::move(prio_cats));
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
reload_adnl_addrs();
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_listening_port(td::uint32 ip, td::int32 port, std::vector<AdnlCategory> cats,
|
|
std::vector<AdnlCategory> prio_cats, td::Promise<td::Unit> promise) {
|
|
td::IPAddress a;
|
|
a.init_ipv4_port(td::IPAddress::ipv4_to_str(ip), static_cast<td::uint16>(port)).ensure();
|
|
auto R = config_.config_del_network_addr(a, std::move(cats), std::move(prio_cats));
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
reload_adnl_addrs();
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_add_proxy(td::uint32 in_ip, td::int32 in_port, td::uint32 out_ip, td::int32 out_port,
|
|
std::shared_ptr<ton::adnl::AdnlProxy> proxy, std::vector<AdnlCategory> cats,
|
|
std::vector<AdnlCategory> prio_cats, td::Promise<td::Unit> promise) {
|
|
td::IPAddress in_addr;
|
|
in_addr.init_ipv4_port(td::IPAddress::ipv4_to_str(in_ip), static_cast<td::uint16>(in_port)).ensure();
|
|
td::IPAddress out_addr;
|
|
out_addr.init_ipv4_port(td::IPAddress::ipv4_to_str(out_ip), static_cast<td::uint16>(out_port)).ensure();
|
|
auto R = config_.config_add_network_addr(in_addr, out_addr, std::move(proxy), std::move(cats), std::move(prio_cats));
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
reload_adnl_addrs();
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::try_del_proxy(td::uint32 ip, td::int32 port, std::vector<AdnlCategory> cats,
|
|
std::vector<AdnlCategory> prio_cats, td::Promise<td::Unit> promise) {
|
|
td::IPAddress a;
|
|
a.init_ipv4_port(td::IPAddress::ipv4_to_str(ip), static_cast<td::uint16>(port)).ensure();
|
|
auto R = config_.config_del_network_addr(a, std::move(cats), std::move(prio_cats));
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
return;
|
|
}
|
|
|
|
if (!R.move_as_ok()) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
|
|
reload_adnl_addrs();
|
|
|
|
write_config(std::move(promise));
|
|
}
|
|
|
|
void ValidatorEngine::check_key(ton::PublicKeyHash id, td::Promise<td::Unit> promise) {
|
|
if (keys_.count(id) == 1) {
|
|
promise.set_value(td::Unit());
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_error(R.move_as_error());
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::got_key, R.move_as_ok());
|
|
promise.set_value(td::Unit());
|
|
}
|
|
});
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::get_public_key, id, std::move(P));
|
|
}
|
|
|
|
td::BufferSlice ValidatorEngine::create_control_query_error(td::Status error) {
|
|
return ton::serialize_tl_object(
|
|
ton::create_tl_object<ton::ton_api::engine_validator_controlQueryError>(error.code(), error.message().str()),
|
|
true);
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getTime &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
auto obj = ton::create_tl_object<ton::ton_api::engine_validator_time>(static_cast<td::int32>(td::Clocks::system()));
|
|
promise.set_value(ton::serialize_tl_object(obj, true));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_importPrivateKey &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (keyring_.empty()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started keyring")));
|
|
return;
|
|
}
|
|
|
|
auto pk = ton::PrivateKey{query.key_};
|
|
auto P = td::PromiseCreator::lambda(
|
|
[promise = std::move(promise), hash = pk.compute_short_id()](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error()));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_keyHash>(hash.tl()), true));
|
|
}
|
|
});
|
|
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_exportPrivateKey &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_unsafe)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (keyring_.empty()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started keyring")));
|
|
return;
|
|
}
|
|
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not implemented")));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_exportPublicKey &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (keyring_.empty()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started keyring")));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error()));
|
|
} else {
|
|
auto pub = R.move_as_ok();
|
|
promise.set_value(ton::serialize_tl_object(pub.tl(), true));
|
|
}
|
|
});
|
|
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::get_public_key, ton::PublicKeyHash{query.key_hash_},
|
|
std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_generateKeyPair &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (keyring_.empty()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started keyring")));
|
|
return;
|
|
}
|
|
|
|
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
|
|
|
auto P = td::PromiseCreator::lambda(
|
|
[promise = std::move(promise), hash = pk.compute_short_id()](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error()));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_keyHash>(hash.tl()), true));
|
|
}
|
|
});
|
|
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addAdnlId &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id, cat = query.category_,
|
|
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add adnl node: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_adnl_node, id, cat, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addDhtId &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda(
|
|
[SelfId = actor_id(this), id, promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add dht node: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_dht_node, id, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addValidatorPermanentKey &query,
|
|
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
|
td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id, election_date = query.election_date_,
|
|
ttl = query.ttl_, promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(
|
|
create_control_query_error(R.move_as_error_prefix("failed to add validator permanent key: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_validator_permanent_key, id, election_date, ttl,
|
|
std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addValidatorTempKey &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P =
|
|
td::PromiseCreator::lambda([SelfId = actor_id(this), perm_key = ton::PublicKeyHash{query.permanent_key_hash_}, id,
|
|
ttl = query.ttl_, promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add validator temp key: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_validator_temp_key, perm_key, id, ttl, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addValidatorAdnlAddress &query,
|
|
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
|
td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this),
|
|
perm_key = ton::PublicKeyHash{query.permanent_key_hash_}, id, ttl = query.ttl_,
|
|
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add validator adnl address: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_validator_adnl_addr, perm_key, id, ttl, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_changeFullNodeAdnlAddress &query,
|
|
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
|
td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.adnl_id_};
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id,
|
|
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to change full node address: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_full_node_adnl_addr, id, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addLiteserver &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id, port = static_cast<td::uint16>(query.port_),
|
|
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add liteserver: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_liteserver, id, port, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addControlInterface &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id, port = static_cast<td::uint16>(query.port_),
|
|
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to get public key: ")));
|
|
return;
|
|
}
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add control interface: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::try_add_control_interface, id, port, std::move(P));
|
|
});
|
|
|
|
check_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delAdnlId &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del adnl node: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
|
|
try_del_adnl_node(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delDhtId &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del adnl node: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
try_del_dht_node(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delValidatorPermanentKey &query,
|
|
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
|
td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del validator permanent key: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
try_del_validator_permanent_key(id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delValidatorTempKey &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del validator temp key: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
try_del_validator_temp_key(ton::PublicKeyHash{query.permanent_key_hash_}, id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delValidatorAdnlAddress &query,
|
|
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
|
td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto id = ton::PublicKeyHash{query.key_hash_};
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del validator adnl addr: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
try_del_validator_adnl_addr(ton::PublicKeyHash{query.permanent_key_hash_}, id, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addListeningPort &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add listening port: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
|
|
try_add_listening_port(query.ip_, query.port_, query.categories_, query.priority_categories_, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delListeningPort &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del listening port: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
|
|
try_del_listening_port(query.ip_, query.port_, query.categories_, query.priority_categories_, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addProxy &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto R = ton::adnl::AdnlProxy::create(*query.proxy_.get());
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("bad proxy type: ")));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to add listening proxy: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
|
|
try_add_proxy(query.in_ip_, query.in_port_, query.out_ip_, query.out_port_, R.move_as_ok(), query.categories_,
|
|
query.priority_categories_, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delProxy &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error_prefix("failed to del listening proxy: ")));
|
|
} else {
|
|
promise.set_value(
|
|
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
});
|
|
|
|
try_del_proxy(query.out_ip_, query.out_port_, query.categories_, query.priority_categories_, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getConfig &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
|
|
auto s = td::json_encode<std::string>(td::ToJson(*config_.tl().get()), true);
|
|
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_jsonConfig>(s));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_sign &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_unsafe)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
LOG(WARNING) << "received sign request: src=" << src.bits256_value().to_hex() << " key=" << query.key_hash_.to_hex()
|
|
<< " string=\n"
|
|
<< td::base64_encode(query.data_.as_slice());
|
|
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error()));
|
|
} else {
|
|
promise.set_value(ton::serialize_tl_object(
|
|
ton::create_tl_object<ton::ton_api::engine_validator_signature>(R.move_as_ok()), true));
|
|
}
|
|
});
|
|
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_message, ton::PublicKeyHash{query.key_hash_},
|
|
std::move(query.data_), std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_setVerbosity &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
|
|
if (query.verbosity_ < 0 || query.verbosity_ > 10) {
|
|
promise.set_value(
|
|
create_control_query_error(td::Status::Error(ton::ErrorCode::error, "verbosity should be in range [0..10]")));
|
|
return;
|
|
}
|
|
|
|
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR) + query.verbosity_);
|
|
|
|
promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getStats &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
|
|
if (validator_manager_.empty()) {
|
|
promise.set_value(
|
|
create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "validator manager not started")));
|
|
return;
|
|
}
|
|
|
|
auto P = td::PromiseCreator::lambda(
|
|
[promise = std::move(promise)](td::Result<std::vector<std::pair<std::string, std::string>>> R) mutable {
|
|
if (R.is_error()) {
|
|
promise.set_value(create_control_query_error(R.move_as_error()));
|
|
} else {
|
|
auto r = R.move_as_ok();
|
|
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_oneStat>> vec;
|
|
for (auto &s : r) {
|
|
vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator_oneStat>(s.first, s.second));
|
|
}
|
|
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_stats>(std::move(vec)));
|
|
}
|
|
});
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::prepare_stats, std::move(P));
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_createElectionBid &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (!started_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
|
return;
|
|
}
|
|
|
|
if (fift_dir_.empty()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "no fift dir")));
|
|
return;
|
|
}
|
|
|
|
td::actor::create_actor<ValidatorElectionBidCreator>("bidcreate", query.election_date_, query.election_addr_,
|
|
query.wallet_, fift_dir_, actor_id(this), keyring_.get(),
|
|
std::move(promise))
|
|
.release();
|
|
}
|
|
|
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_checkDhtServers &query, td::BufferSlice data,
|
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
|
return;
|
|
}
|
|
if (keyring_.empty()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "keyring not started")));
|
|
return;
|
|
}
|
|
if (!dht_config_) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "no dht config")));
|
|
return;
|
|
}
|
|
|
|
if (config_.adnl_ids.count(ton::PublicKeyHash{query.id_}) == 0) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "no dht config")));
|
|
return;
|
|
}
|
|
|
|
td::actor::create_actor<CheckDhtServerStatusQuery>("pinger", dht_config_, ton::adnl::AdnlNodeIdShort{query.id_},
|
|
adnl_.get(), std::move(promise))
|
|
.release();
|
|
}
|
|
|
|
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
|
|
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
|
td::Promise<td::BufferSlice> promise) {
|
|
auto it = control_permissions_.find(CI_key{dst.pubkey_hash(), port, src.pubkey_hash()});
|
|
if (it == control_permissions_.end()) {
|
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "forbidden")));
|
|
return;
|
|
}
|
|
|
|
auto E = ton::fetch_tl_object<ton::lite_api::liteServer_query>(data.clone(), true);
|
|
if (E.is_ok()) {
|
|
if (!started_) {
|
|
return;
|
|
}
|
|
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::run_ext_query,
|
|
std::move(data), std::move(promise));
|
|
return;
|
|
}
|
|
|
|
auto G = ton::fetch_tl_object<ton::ton_api::engine_validator_controlQuery>(std::move(data), true);
|
|
if (G.is_error()) {
|
|
promise.set_value(create_control_query_error(G.move_as_error_prefix("failed to parse validator query: ")));
|
|
return;
|
|
}
|
|
|
|
data = std::move(G.move_as_ok()->data_);
|
|
auto F = ton::fetch_tl_object<ton::ton_api::Function>(data.clone(), true);
|
|
if (F.is_error()) {
|
|
promise.set_value(create_control_query_error(F.move_as_error_prefix("failed to parse validator query: ")));
|
|
return;
|
|
}
|
|
auto f = F.move_as_ok();
|
|
|
|
ton::ton_api::downcast_call(*f.get(), [&](auto &obj) {
|
|
run_control_query(obj, std::move(data), src.pubkey_hash(), it->second, std::move(promise));
|
|
});
|
|
}
|
|
|
|
void ValidatorEngine::run() {
|
|
td::mkdir(db_root_).ensure();
|
|
ton::errorlog::ErrorLog::create(db_root_);
|
|
|
|
auto Sr = load_global_config();
|
|
if (Sr.is_error()) {
|
|
LOG(ERROR) << "failed to load global config'" << global_config_ << "': " << Sr;
|
|
std::_Exit(2);
|
|
}
|
|
|
|
keyring_ = ton::keyring::Keyring::create(db_root_ + "/keyring");
|
|
// TODO wait for password
|
|
started_keyring_ = true;
|
|
|
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
|
if (R.is_error()) {
|
|
LOG(ERROR) << "failed to parse config: " << R.move_as_error();
|
|
std::_Exit(2);
|
|
} else {
|
|
td::actor::send_closure(SelfId, &ValidatorEngine::start);
|
|
}
|
|
});
|
|
load_config(std::move(P));
|
|
}
|
|
|
|
std::atomic<bool> need_stats_flag{false};
|
|
void need_stats(int sig) {
|
|
need_stats_flag.store(true);
|
|
}
|
|
std::atomic<bool> rotate_logs_flags{false};
|
|
void force_rotate_logs(int sig) {
|
|
rotate_logs_flags.store(true);
|
|
}
|
|
|
|
void dump_memory_stats() {
|
|
if (!is_memprof_on()) {
|
|
return;
|
|
}
|
|
LOG(WARNING) << "memory_dump";
|
|
std::vector<AllocInfo> v;
|
|
dump_alloc([&](const AllocInfo &info) { v.push_back(info); });
|
|
std::sort(v.begin(), v.end(), [](const AllocInfo &a, const AllocInfo &b) { return a.size > b.size; });
|
|
size_t total_size = 0;
|
|
size_t other_size = 0;
|
|
int cnt = 0;
|
|
for (auto &info : v) {
|
|
if (cnt++ < 50) {
|
|
LOG(WARNING) << td::format::as_size(info.size) << td::format::as_array(info.backtrace);
|
|
} else {
|
|
other_size += info.size;
|
|
}
|
|
total_size += info.size;
|
|
}
|
|
LOG(WARNING) << td::tag("other", td::format::as_size(other_size));
|
|
LOG(WARNING) << td::tag("total", td::format::as_size(total_size));
|
|
LOG(WARNING) << td::tag("total traces", get_ht_size());
|
|
LOG(WARNING) << td::tag("fast_backtrace_success_rate", get_fast_backtrace_success_rate());
|
|
}
|
|
|
|
void dump_stats() {
|
|
dump_memory_stats();
|
|
LOG(WARNING) << td::NamedThreadSafeCounter::get_default();
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
SET_VERBOSITY_LEVEL(verbosity_INFO);
|
|
|
|
td::set_default_failure_signal_handler().ensure();
|
|
|
|
td::actor::ActorOwn<ValidatorEngine> x;
|
|
td::unique_ptr<td::LogInterface> logger_;
|
|
SCOPE_EXIT {
|
|
td::log_interface = td::default_log_interface;
|
|
};
|
|
|
|
std::vector<std::function<void()>> acts;
|
|
|
|
td::OptionsParser p;
|
|
p.set_description("validator or full node for TON network");
|
|
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
|
|
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
|
|
SET_VERBOSITY_LEVEL(v);
|
|
return td::Status::OK();
|
|
});
|
|
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('C', "global-config", "file to read global config", [&](td::Slice fname) {
|
|
acts.push_back(
|
|
[&x, fname = fname.str()]() { td::actor::send_closure(x, &ValidatorEngine::set_global_config, fname); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
|
|
acts.push_back(
|
|
[&x, fname = fname.str()]() { td::actor::send_closure(x, &ValidatorEngine::set_local_config, fname); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('I', "ip", "ip:port of instance", [&](td::Slice arg) {
|
|
td::IPAddress addr;
|
|
TRY_STATUS(addr.init_host_port(arg.str()));
|
|
acts.push_back([&x, addr]() { td::actor::send_closure(x, &ValidatorEngine::add_ip, addr); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
|
|
acts.push_back([&x, fname = fname.str()]() { td::actor::send_closure(x, &ValidatorEngine::set_db_root, fname); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('f', "fift-dir", "directory with fift scripts", [&](td::Slice fname) {
|
|
acts.push_back([&x, fname = fname.str()]() { td::actor::send_closure(x, &ValidatorEngine::set_fift_dir, fname); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('F', "filedb-depth",
|
|
"depth of autodirs for blocks, proofs, etc. Default value is 2. You need to clear the "
|
|
"database, if you need to change this option",
|
|
[&](td::Slice fname) {
|
|
acts.push_back([&x, fname = fname.str()]() {
|
|
td::actor::send_closure(x, &ValidatorEngine::set_db_depth, td::to_integer<td::uint32>(fname));
|
|
});
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
|
|
#if TD_DARWIN || TD_LINUX
|
|
close(0);
|
|
setsid();
|
|
#endif
|
|
td::set_signal_handler(td::SignalType::HangUp, force_rotate_logs).ensure();
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
|
|
logger_ = td::TsFileLog::create(fname.str()).move_as_ok();
|
|
td::log_interface = logger_.get();
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('s', "state-ttl", "state will be gc'd after this time (in seconds) default=3600", [&](td::Slice fname) {
|
|
auto v = td::to_double(fname);
|
|
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_state_ttl, v); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('b', "block-ttl", "blocks will be gc'd after this time (in seconds) default=7*86400",
|
|
[&](td::Slice fname) {
|
|
auto v = td::to_double(fname);
|
|
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_block_ttl, v); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('A', "archive-ttl", "archived blocks will be deleted after this time (in seconds) default=365*86400",
|
|
[&](td::Slice fname) {
|
|
auto v = td::to_double(fname);
|
|
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_archive_ttl, v); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('K', "key-proof-ttl", "key blocks will be deleted after this time (in seconds) default=365*86400*10",
|
|
[&](td::Slice fname) {
|
|
auto v = td::to_double(fname);
|
|
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_key_proof_ttl, v); });
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('S', "sync-before", "in initial sync download all blocks for last given seconds default=3600",
|
|
[&](td::Slice fname) {
|
|
auto v = td::to_double(fname);
|
|
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_sync_ttl, v); });
|
|
return td::Status::OK();
|
|
});
|
|
td::uint32 threads = 7;
|
|
p.add_option('t', "threads", PSTRING() << "number of threads (default=" << threads << ")", [&](td::Slice fname) {
|
|
td::int32 v;
|
|
try {
|
|
v = std::stoi(fname.str());
|
|
} catch (...) {
|
|
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: not a number");
|
|
}
|
|
if (v < 1 || v > 256) {
|
|
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: should be in range [1..256]");
|
|
}
|
|
threads = v;
|
|
return td::Status::OK();
|
|
});
|
|
p.add_option('u', "user", "change user", [&](td::Slice user) { return td::change_user(user); });
|
|
auto S = p.run(argc, argv);
|
|
if (S.is_error()) {
|
|
LOG(ERROR) << "failed to parse options: " << S.move_as_error();
|
|
std::_Exit(2);
|
|
}
|
|
|
|
td::set_runtime_signal_handler(1, need_stats).ensure();
|
|
|
|
td::actor::Scheduler scheduler({threads});
|
|
|
|
scheduler.run_in_context([&] {
|
|
CHECK(vm::init_op_cp0());
|
|
x = td::actor::create_actor<ValidatorEngine>("validator-engine");
|
|
for (auto &act : acts) {
|
|
act();
|
|
}
|
|
acts.clear();
|
|
td::actor::send_closure(x, &ValidatorEngine::run);
|
|
});
|
|
while (scheduler.run(1)) {
|
|
if (need_stats_flag.exchange(false)) {
|
|
dump_stats();
|
|
}
|
|
if (rotate_logs_flags.exchange(false)) {
|
|
if (td::log_interface) {
|
|
td::log_interface->rotate();
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|