1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-13 11:42:18 +00:00

Use partial liteservers in tonlib and lite-client

This commit is contained in:
SpyCheese 2023-01-11 19:14:03 +03:00
parent 1ccf25d6b7
commit 2ea17ec03b
17 changed files with 891 additions and 974 deletions

File diff suppressed because it is too large Load diff

View file

@ -57,8 +57,7 @@ class TestNode : public td::actor::Actor {
bool client_ready = false;
std::vector<td::Promise<td::Unit>> wait_client_ready;
int max_common_prefix(ton::ShardIdFull shard) const;
bool supports_shard(ton::ShardIdFull shard) const;
bool supports(ton::ShardIdFull shard) const;
};
std::vector<LiteServer> servers_;
@ -352,9 +351,6 @@ class TestNode : public td::actor::Actor {
bool parse_shard_id(ton::ShardIdFull& shard);
bool parse_block_id_ext(ton::BlockIdExt& blkid, bool allow_incomplete = false);
bool parse_block_id_ext(std::string blk_id_string, ton::BlockIdExt& blkid, bool allow_incomplete = false) const;
bool parse_stack_value(td::Slice str, vm::StackEntry& value);
bool parse_stack_value(vm::StackEntry& value);
bool parse_stack_values(std::vector<vm::StackEntry>& values);
bool register_blkid(const ton::BlockIdExt& blkid);
bool show_new_blkids(bool all = false);
bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const;
@ -458,8 +454,7 @@ class TestNode : public td::actor::Actor {
void parse_line(td::BufferSlice data);
TestNode() {
}
TestNode() = default;
void run();
};

Binary file not shown.

Binary file not shown.

View file

@ -8,7 +8,6 @@ set(TONLIB_SOURCE
tonlib/Client.cpp
tonlib/Config.cpp
tonlib/ExtClient.cpp
tonlib/ExtClientMulti.cpp
tonlib/ExtClientLazy.cpp
tonlib/ExtClientOutbound.cpp
tonlib/KeyStorage.cpp
@ -24,8 +23,7 @@ set(TONLIB_SOURCE
tonlib/Client.h
tonlib/Config.h
tonlib/ExtClient.h
tonlib/ExtClientMulti.h
tonlib/ExtClientRaw.h
tonlib/ExtClientLazy.h
tonlib/ExtClientOutbound.h
tonlib/KeyStorage.h
tonlib/KeyValue.h

View file

@ -66,16 +66,16 @@ td::Result<Config> Config::parse(std::string str) {
return td::Status::Error("Invalid config (1)");
}
td::JsonArray empty_array;
TRY_RESULT(lite_clients_obj,
TRY_RESULT(lite_servers_obj,
td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, true));
auto &lite_clients =
lite_clients_obj.type() == td::JsonValue::Type::Array ? lite_clients_obj.get_array() : empty_array;
TRY_RESULT(lite_clients_v2_obj,
auto &lite_servers =
lite_servers_obj.type() == td::JsonValue::Type::Array ? lite_servers_obj.get_array() : empty_array;
TRY_RESULT(lite_servers_v2_obj,
td::get_json_object_field(json.get_object(), "liteservers_v2", td::JsonValue::Type::Array, true));
auto &lite_clients_v2 =
lite_clients_v2_obj.type() == td::JsonValue::Type::Array ? lite_clients_v2_obj.get_array() : empty_array;
auto &lite_servers_v2 =
lite_servers_v2_obj.type() == td::JsonValue::Type::Array ? lite_servers_v2_obj.get_array() : empty_array;
auto parse_desc = [&](td::JsonValue& value) -> td::Result<Config::LiteClient> {
auto parse_desc = [&](td::JsonValue &value) -> td::Result<Config::LiteServer> {
if (value.type() != td::JsonValue::Type::Object) {
return td::Status::Error("Invalid config (2)");
}
@ -83,8 +83,8 @@ td::Result<Config> Config::parse(std::string str) {
TRY_RESULT(ip, td::get_json_object_long_field(object, "ip", false));
TRY_RESULT(port, td::get_json_object_int_field(object, "port", false));
Config::LiteClient client;
TRY_STATUS(client.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast<td::int32>(ip)), port));
Config::LiteServer server;
TRY_STATUS(server.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast<td::int32>(ip)), port));
TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false));
auto &id = id_obj.get_object();
@ -98,20 +98,19 @@ td::Result<Config> Config::parse(std::string str) {
return td::Status::Error("Invalid config (4)");
}
client.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
return client;
server.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
return server;
};
Config res;
for (auto &value : lite_clients) {
TRY_RESULT(client, parse_desc(value));
res.lite_clients.push_back(std::move(client));
for (auto &value : lite_servers) {
TRY_RESULT(server, parse_desc(value));
res.lite_servers.push_back(std::move(server));
}
for (auto &value : lite_clients_v2) {
TRY_RESULT(client, parse_desc(value));
client.is_full = false;
TRY_RESULT(shards_obj,
td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false));
for (auto &value : lite_servers_v2) {
TRY_RESULT(server, parse_desc(value));
server.is_full = false;
TRY_RESULT(shards_obj, td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false));
for (auto &shard : shards_obj.get_array()) {
if (shard.type() != td::JsonValue::Type::Object) {
return td::Status::Error("Invalid config (5)");
@ -122,10 +121,10 @@ td::Result<Config> Config::parse(std::string str) {
if (shard_id == 0) {
return td::Status::Error("Invalid config (6)");
}
client.shards.emplace_back(workchain, shard_id);
server.shards.emplace_back(workchain, shard_id);
}
res.lite_clients.push_back(std::move(client));
res.lite_servers.push_back(std::move(server));
}
TRY_RESULT(validator_obj,

View file

@ -23,7 +23,7 @@
namespace tonlib {
struct Config {
struct LiteClient {
struct LiteServer {
ton::adnl::AdnlNodeIdFull adnl_id;
td::IPAddress address;
bool is_full = true;
@ -32,7 +32,7 @@ struct Config {
ton::BlockIdExt zero_state_id;
ton::BlockIdExt init_block_id;
std::vector<ton::BlockIdExt> hardforks;
std::vector<LiteClient> lite_clients;
std::vector<LiteServer> lite_servers;
std::string name;
static td::Result<Config> parse(std::string str);
};

View file

@ -54,7 +54,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
}
void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) {
auto query_id = queries_.create(std::move(promise));
td::Promise<td::BufferSlice> P = [query_id, self = this,
actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) {
@ -65,7 +65,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlic
if (client_.adnl_ext_client_.empty()) {
return P.set_error(TonlibError::NoLiteServers());
}
td::actor::send_closure(client_.adnl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
td::Timestamp::in(10.0), std::move(P));
td::actor::send_closure(client_.adnl_ext_client_, &ExtClientLazy::send_query, "query", std::move(query),
shard, td::Timestamp::in(10.0), std::move(P));
}
} // namespace tonlib

View file

@ -32,7 +32,6 @@
#include "TonlibError.h"
#include "utils.h"
#include "QueryTraits.h"
#include "ExtClientRaw.h"
namespace tonlib {
class LastBlock;

View file

@ -19,14 +19,26 @@
#include "ExtClientLazy.h"
#include "TonlibError.h"
#include "td/utils/Random.h"
#include "ton/ton-shard.h"
#include <map>
namespace tonlib {
class ExtClientLazyImp : public ExtClientLazy {
class ExtClientLazyImpl : public ExtClientLazy {
public:
ExtClientLazyImp(std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers,
td::unique_ptr<ExtClientLazy::Callback> callback)
: servers_(std::move(servers)), callback_(std::move(callback)) {
CHECK(!servers_.empty());
ExtClientLazyImpl(std::vector<Config::LiteServer> servers, td::unique_ptr<ExtClientLazy::Callback> callback)
: callback_(std::move(callback)) {
CHECK(!servers.empty());
servers_.resize(servers.size());
for (size_t i = 0; i < servers_.size(); ++i) {
servers_[i].s = std::move(servers[i]);
if (!servers_[i].s.is_full) {
for (auto shard : servers_[i].s.shards) {
CHECK(shard.is_valid_ext());
max_server_shard_depth_ = std::max(max_server_shard_depth_, shard.pfx_len());
}
}
}
}
void start_up() override {
@ -34,29 +46,21 @@ class ExtClientLazyImp : public ExtClientLazy {
td::random_shuffle(td::as_mutable_span(servers_), rnd);
}
void check_ready(td::Promise<td::Unit> promise) override {
before_query();
if (client_.empty()) {
return promise.set_error(TonlibError::Cancelled());
}
send_closure(client_, &ton::adnl::AdnlExtClient::check_ready, std::move(promise));
}
void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
before_query();
if (client_.empty()) {
return promise.set_error(TonlibError::Cancelled());
}
td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), idx = cur_server_idx_,
TRY_RESULT_PROMISE(promise, server_idx, before_query(shard));
auto& server = servers_[server_idx];
CHECK(!server.client.empty());
alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), server_idx,
promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error() &&
(R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
td::actor::send_closure(SelfId, &ExtClientLazyImp::set_server_bad, idx, true);
td::actor::send_closure(SelfId, &ExtClientLazyImpl::set_server_bad, server_idx);
}
promise.set_result(std::move(R));
};
send_closure(client_, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
std::move(P));
}
@ -64,64 +68,124 @@ class ExtClientLazyImp : public ExtClientLazy {
if (servers_.size() == 1) {
return;
}
cur_server_bad_ = cur_server_bad_force_ = true;
auto it = shard_to_server_.find(ton::ShardIdFull(ton::masterchainId));
if (it != shard_to_server_.end()) {
set_server_bad(it->second);
}
}
private:
void before_query() {
td::Result<size_t> before_query(ton::ShardIdFull shard) {
if (!shard.is_valid_ext()) {
return td::Status::Error("Invalid shard");
}
if (is_closing_) {
return;
return td::Status::Error("Client is closing");
}
alarm_timestamp() = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT);
if (cur_server_bad_) {
++cur_server_idx_;
} else if (!client_.empty()) {
return;
if (shard.pfx_len() > max_server_shard_depth_) {
shard = shard_prefix(shard, max_server_shard_depth_);
}
auto it = shard_to_server_.find(shard);
if (it != shard_to_server_.end()) {
size_t server_idx = it->second;
if (!servers_[server_idx].client.empty()) {
return server_idx;
}
shard_to_server_.erase(it);
}
size_t server_idx = servers_.size();
int cnt = 0;
int best_priority = -1;
for (size_t i = 0; i < servers_.size(); ++i) {
Server& server = servers_[i];
if (!server.supports(shard)) {
continue;
}
int priority = 0;
priority += (server.client.empty() ? 0 : 100);
priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10);
priority += (server.s.is_full ? 1 : 0);
if (priority < best_priority) {
continue;
}
if (priority > best_priority) {
best_priority = priority;
cnt = 0;
}
if (td::Random::fast(0, cnt) == 0) {
server_idx = i;
}
++cnt;
}
if (server_idx == servers_.size()) {
return td::Status::Error(PSTRING() << "No liteserver for shard " << shard.to_str());
}
Server& server = servers_[server_idx];
if (!server.client.empty()) {
return server_idx;
}
class Callback : public ton::adnl::AdnlExtClient::Callback {
public:
explicit Callback(td::actor::ActorShared<ExtClientLazyImp> parent, size_t idx)
explicit Callback(td::actor::ActorShared<ExtClientLazyImpl> parent, size_t idx)
: parent_(std::move(parent)), idx_(idx) {
}
void on_ready() override {
td::actor::send_closure(parent_, &ExtClientLazyImp::set_server_bad, idx_, false);
}
void on_stop_ready() override {
td::actor::send_closure(parent_, &ExtClientLazyImp::set_server_bad, idx_, true);
td::actor::send_closure(parent_, &ExtClientLazyImpl::set_server_bad, idx_);
}
private:
td::actor::ActorShared<ExtClientLazyImp> parent_;
td::actor::ActorShared<ExtClientLazyImpl> parent_;
size_t idx_;
};
ref_cnt_++;
cur_server_bad_ = false;
cur_server_bad_force_ = false;
const auto& s = servers_[cur_server_idx_ % servers_.size()];
LOG(INFO) << "Connecting to liteserver " << s.second;
client_ = ton::adnl::AdnlExtClient::create(
s.first, s.second, std::make_unique<Callback>(td::actor::actor_shared(this), cur_server_idx_));
if (shard.is_masterchain()) {
LOG(INFO) << "Connecting to liteserver " << server.s.address << " for masterchain";
} else {
LOG(INFO) << "Connecting to liteserver " << server.s.address << " for shard " << shard.to_str();
}
server.client = ton::adnl::AdnlExtClient::create(
server.s.adnl_id, server.s.address, std::make_unique<Callback>(td::actor::actor_shared(this), server_idx));
alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
return server_idx;
}
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers_;
size_t cur_server_idx_ = 0;
bool cur_server_bad_ = false;
bool cur_server_bad_force_ = false;
struct Server {
Config::LiteServer s;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
td::Timestamp timeout = td::Timestamp::never();
td::Timestamp ignore_until = td::Timestamp::never();
bool supports(const ton::ShardIdFull& shard) const {
return s.is_full || shard.is_masterchain() ||
std::any_of(s.shards.begin(), s.shards.end(),
[&](const ton::ShardIdFull s_shard) { return ton::shard_intersects(shard, s_shard); });
}
};
std::vector<Server> servers_;
std::map<ton::ShardIdFull, size_t> shard_to_server_;
int max_server_shard_depth_ = 0;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client_;
td::unique_ptr<ExtClientLazy::Callback> callback_;
static constexpr double MAX_NO_QUERIES_TIMEOUT = 100;
bool is_closing_{false};
td::uint32 ref_cnt_{1};
void set_server_bad(size_t idx, bool bad) {
if (idx == cur_server_idx_ && servers_.size() > 1 && !cur_server_bad_force_) {
cur_server_bad_ = bad;
void alarm() override {
for (Server& server : servers_) {
if (server.timeout && server.timeout.is_in_past()) {
server.client.reset();
}
}
}
void alarm() override {
client_.reset();
void set_server_bad(size_t idx) {
servers_[idx].client.reset();
servers_[idx].timeout = td::Timestamp::never();
servers_[idx].ignore_until = td::Timestamp::in(60.0);
}
void hangup_shared() override {
ref_cnt_--;
@ -130,7 +194,9 @@ class ExtClientLazyImp : public ExtClientLazy {
void hangup() override {
is_closing_ = true;
ref_cnt_--;
client_.reset();
for (Server& server : servers_) {
server.client.reset();
}
try_stop();
}
void try_stop() {
@ -142,11 +208,11 @@ class ExtClientLazyImp : public ExtClientLazy {
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
td::unique_ptr<Callback> callback) {
return create({std::make_pair(dst, dst_addr)}, std::move(callback));
return create({Config::LiteServer{dst, dst_addr, true, {}}}, std::move(callback));
}
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers, td::unique_ptr<Callback> callback) {
return td::actor::create_actor<ExtClientLazyImp>("ExtClientLazy", std::move(servers), std::move(callback));
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(std::vector<Config::LiteServer> servers,
td::unique_ptr<Callback> callback) {
return td::actor::create_actor<ExtClientLazyImpl>("ExtClientLazy", std::move(servers), std::move(callback));
}
} // namespace tonlib

View file

@ -18,23 +18,27 @@
*/
#pragma once
#include "td/actor/actor.h"
#include "adnl/adnl-ext-client.h"
#include "ton/ton-types.h"
#include "adnl/adnl-ext-client.h"
#include "Config.h"
namespace tonlib {
class ExtClientLazy : public ton::adnl::AdnlExtClient {
class ExtClientLazy : public td::actor::Actor {
public:
class Callback {
public:
virtual ~Callback() = default;
virtual ~Callback() {
}
};
virtual void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) = 0;
virtual void force_change_liteserver() = 0;
static td::actor::ActorOwn<ExtClientLazy> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
td::unique_ptr<Callback> callback);
static td::actor::ActorOwn<ExtClientLazy> create(
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers, td::unique_ptr<Callback> callback);
static td::actor::ActorOwn<ExtClientLazy> create(std::vector<Config::LiteServer> servers,
td::unique_ptr<Callback> callback);
};
} // namespace tonlib

View file

@ -1,169 +0,0 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ExtClientMulti.h"
#include "ton/ton-shard.h"
#include "td/utils/Random.h"
namespace tonlib {
static const double MAX_NO_QUERIES_TIMEOUT = 120;
ExtClientMulti::ExtClientMulti(std::vector<Config::LiteClient> clients, td::unique_ptr<Callback> callback)
: callback_(std::move(callback)) {
for (auto &desc : clients) {
servers_.emplace_back();
servers_.back().desc = std::move(desc);
}
}
void ExtClientMulti::start_up() {
alarm_timestamp() = td::Timestamp::in(60.0);
}
void ExtClientMulti::send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
if (shard.is_masterchain() && mc_server_idx_ != -1 && !servers_[mc_server_idx_].is_bad()) {
send_query_to_server(std::move(name), std::move(data), mc_server_idx_, timeout, std::move(promise));
return;
}
auto it = shard_server_idx_cached_.find(shard);
if (it != shard_server_idx_cached_.end() && !servers_[it->second].is_bad()) {
send_query_to_server(std::move(name), std::move(data), it->second, timeout, std::move(promise));
return;
}
int server_idx = -1;
int random_idx = -1;
int cnt = 0;
int best_prefix = -1;
for (int i = 0; i < (int)servers_.size(); ++i) {
const Server &server = servers_[i];
if (server.is_bad()) {
continue;
}
int len = server.desc.is_full ? 65 : server.max_supported_prefix(shard);
if (len > best_prefix) {
best_prefix = len;
server_idx = -1;
random_idx = -1;
cnt = 0;
} else if (len < best_prefix) {
continue;
}
if (!server.client.empty()) {
server_idx = i;
}
if (td::Random::fast(0, cnt) == 0) {
random_idx = i;
}
++cnt;
}
if (server_idx == -1) {
server_idx = random_idx;
}
if (server_idx == -1) {
promise.set_error(td::Status::Error("failed to select a suitable server"));
return;
}
if (shard.pfx_len() <= ton::max_shard_pfx_len) {
shard_server_idx_cached_[shard] = server_idx;
}
if (shard.is_masterchain() || servers_[server_idx].desc.is_full) {
mc_server_idx_ = server_idx;
}
send_query_to_server(std::move(name), std::move(data), server_idx, timeout, std::move(promise));
}
void ExtClientMulti::send_query_to_server(std::string name, td::BufferSlice data, int server_idx, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
Server &server = servers_.at(server_idx);
if (server.client.empty()) {
start_client(server_idx);
}
server.ttl = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT);
td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), idx = server_idx,
promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error() &&
(R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
td::actor::send_closure(SelfId, &ExtClientMulti::set_server_bad, idx);
}
promise.set_result(std::move(R));
};
send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
std::move(P));
}
void ExtClientMulti::force_change_liteserver() {
if (mc_server_idx_ != -1) {
set_server_bad(mc_server_idx_);
mc_server_idx_ = -1;
}
}
void ExtClientMulti::start_client(int server_idx) {
class Callback : public ton::adnl::AdnlExtClient::Callback {
public:
Callback(td::actor::ActorId<ExtClientMulti> parent, int idx) : parent_(std::move(parent)), idx_(idx) {
}
void on_ready() override {
}
void on_stop_ready() override {
td::actor::send_closure(parent_, &ExtClientMulti::set_server_bad, idx_);
}
private:
td::actor::ActorId<ExtClientMulti> parent_;
int idx_;
};
Server &server = servers_.at(server_idx);
server.client = ton::adnl::AdnlExtClient::create(server.desc.adnl_id, server.desc.address,
std::make_unique<Callback>(actor_id(this), server_idx));
}
void ExtClientMulti::alarm() {
for (Server& server : servers_) {
if (server.ttl && server.ttl.is_in_past()) {
server.client.reset();
}
}
alarm_timestamp() = td::Timestamp::in(60.0);
}
void ExtClientMulti::set_server_bad(int idx) {
Server& server = servers_.at(idx);
server.client.reset();
server.ttl = td::Timestamp::never();
server.ignore_until = td::Timestamp::in(10.0);
}
int ExtClientMulti::Server::max_supported_prefix(ton::ShardIdFull shard) const {
if (desc.is_full || shard.is_masterchain()) {
return shard.pfx_len();
}
int res = -1;
for (const ton::ShardIdFull &our_shard : desc.shards) {
if (ton::shard_is_ancestor(our_shard, shard)) {
return shard.pfx_len();
}
if (shard.workchain == our_shard.workchain) {
int x = std::min({shard.pfx_len(), our_shard.pfx_len(), ton::count_matching_bits(shard.shard, our_shard.shard)});
res = std::max(res, x);
}
}
return res;
}
} // namespace tonlib

View file

@ -1,61 +0,0 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "td/actor/actor.h"
#include "adnl/adnl-ext-client.h"
#include "Config.h"
#include "ExtClientRaw.h"
#include <map>
namespace tonlib {
class ExtClientMulti : public ExtClientRaw {
public:
ExtClientMulti(std::vector<Config::LiteClient> clients, td::unique_ptr<Callback> callback);
void start_up() override;
void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override;
void alarm() override;
void force_change_liteserver() override;
private:
void send_query_to_server(std::string name, td::BufferSlice data, int server_idx, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise);
void start_client(int server_idx);
struct Server {
Config::LiteClient desc;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
td::Timestamp ttl;
td::Timestamp ignore_until = td::Timestamp::never();
int max_supported_prefix(ton::ShardIdFull shard) const;
bool is_bad() const {
return ignore_until && !ignore_until.is_in_past();
}
};
void set_server_bad(int idx);
td::unique_ptr<Callback> callback_;
std::vector<Server> servers_;
int mc_server_idx_ = -1;
std::map<ton::ShardIdFull, int> shard_server_idx_cached_;
};
} // namespace tonlib

View file

@ -20,11 +20,12 @@
#include "ExtClientOutbound.h"
#include "TonlibError.h"
#include <map>
namespace tonlib {
class ExtClientOutboundImp : public ExtClientOutbound {
class ExtClientOutboundImpl : public ExtClientOutbound {
public:
ExtClientOutboundImp(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
}
void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
@ -37,9 +38,6 @@ class ExtClientOutboundImp : public ExtClientOutbound {
void force_change_liteserver() override {
}
void force_change_liteserver() override {
}
void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
auto it = queries_.find(id);
if (it == queries_.end()) {
@ -65,6 +63,6 @@ class ExtClientOutboundImp : public ExtClientOutbound {
};
td::actor::ActorOwn<ExtClientOutbound> ExtClientOutbound::create(td::unique_ptr<Callback> callback) {
return td::actor::create_actor<ExtClientOutboundImp>("ExtClientOutbound", std::move(callback));
return td::actor::create_actor<ExtClientOutboundImpl>("ExtClientOutbound", std::move(callback));
}
} // namespace tonlib

View file

@ -30,6 +30,7 @@ class ExtClientOutbound : public ExtClientLazy {
}
virtual void request(td::int64 id, std::string data, ton::ShardIdFull shard) = 0;
};
virtual void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) = 0;
static td::actor::ActorOwn<ExtClientOutbound> create(td::unique_ptr<Callback> callback);
};

View file

@ -27,7 +27,6 @@
#include "tonlib/keys/Mnemonic.h"
#include "tonlib/keys/SimpleEncryption.h"
#include "tonlib/TonlibError.h"
#include "tonlib/ExtClientMulti.h"
#include "smc-envelope/GenericAccount.h"
#include "smc-envelope/ManualDns.h"
@ -863,7 +862,9 @@ class Query {
}
return res;
}
td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig, std::shared_ptr<const block::Config>& cfg, vm::Dictionary& libraries) {
td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig,
std::shared_ptr<const block::Config>& cfg,
vm::Dictionary& libraries) {
// gas fees
bool is_masterchain = raw_.source->get_address().workchain == ton::masterchainId;
TRY_RESULT(gas_limits_prices, cfg->get_gas_limits_prices(is_masterchain));
@ -892,7 +893,8 @@ class Query {
.set_now(raw_.source->get_sync_time())
.set_ignore_chksig(ignore_chksig)
.set_address(raw_.source->get_address())
.set_config(cfg).set_libraries(libraries));
.set_config(cfg)
.set_libraries(libraries));
td::int64 fwd_fee = 0;
if (res.success) {
LOG(DEBUG) << "output actions:\n"
@ -962,8 +964,9 @@ td::Result<td::int64> to_balance(td::Ref<vm::CellSlice> balance_ref) {
class GetTransactionHistory : public td::actor::Actor {
public:
GetTransactionHistory(ExtClientRef ext_client_ref, block::StdAddress address, ton::LogicalTime lt, ton::Bits256 hash, td::int32 count,
td::actor::ActorShared<> parent, td::Promise<block::TransactionList::Info> promise)
GetTransactionHistory(ExtClientRef ext_client_ref, block::StdAddress address, ton::LogicalTime lt, ton::Bits256 hash,
td::int32 count, td::actor::ActorShared<> parent,
td::Promise<block::TransactionList::Info> promise)
: address_(std::move(address))
, lt_(std::move(lt))
, hash_(std::move(hash))
@ -1671,8 +1674,8 @@ void TonlibClient::init_ext_client() {
}
void request(td::int64 id, std::string data, ton::ShardIdFull shard) override {
send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff),
std::move(data), shard);
send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), std::move(data),
shard);
}
private:
@ -1685,34 +1688,17 @@ void TonlibClient::init_ext_client() {
ext_client_outbound_ = client.get();
raw_client_ = std::move(client);
} else {
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers;
for (const auto& s : config_.lite_clients) {
servers.emplace_back(s.adnl_id, s.address);
}
class Callback : public ExtClientLazy::Callback {
public:
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
}
private:
td::actor::ActorShared<> parent_;
};
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> full_servers;
for (const auto& s : config_.lite_clients) {
if (s.is_full) {
full_servers.emplace_back(s.adnl_id, s.address);
}
}
if (!full_servers.empty()) {
raw_client_ =
ExtClientRaw::create(std::move(full_servers), td::make_unique<Callback>(td::actor::actor_shared()));
} else {
CHECK(!config_.lite_clients.empty());
raw_client_ = td::actor::create_actor<ExtClientMulti>("ExtClientMulti", config_.lite_clients,
td::make_unique<Callback>(td::actor::actor_shared()));
}
ext_client_outbound_ = {};
ref_cnt_++;
raw_client_ = ExtClientLazy::create(std::move(servers), td::make_unique<Callback>(td::actor::actor_shared()));
raw_client_ = ExtClientLazy::create(config_.lite_servers, td::make_unique<Callback>(td::actor::actor_shared()));
}
}
@ -2360,7 +2346,7 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
TRY_RESULT_PREFIX(new_config, Config::parse(std::move(config->config_)),
TonlibError::InvalidConfig("can't parse config"));
if (new_config.lite_clients.empty() && !config->use_callbacks_for_network_) {
if (new_config.lite_servers.empty() && !config->use_callbacks_for_network_) {
return TonlibError::InvalidConfig("no lite clients");
}
td::optional<Config> o_master_config;
@ -2427,8 +2413,7 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
state.vert_seqno = vert_seqno;
bool user_defined_init_block = false;
if (new_config.init_block_id.is_valid() &&
state.last_key_block_id.id.seqno < new_config.init_block_id.id.seqno) {
if (new_config.init_block_id.is_valid() && state.last_key_block_id.id.seqno < new_config.init_block_id.id.seqno) {
state.last_key_block_id = new_config.init_block_id;
user_defined_init_block = true;
LOG(INFO) << "Use init block from USER config: " << new_config.init_block_id.to_str();
@ -2524,8 +2509,7 @@ td::Result<std::string> to_std_address(td::Ref<vm::CellSlice> cs) {
}
struct ToRawTransactions {
explicit ToRawTransactions(td::optional<td::Ed25519::PrivateKey> private_key, bool try_decode_messages = true)
: private_key_(std::move(private_key))
, try_decode_messages_(try_decode_messages) {
: private_key_(std::move(private_key)), try_decode_messages_(try_decode_messages) {
}
td::optional<td::Ed25519::PrivateKey> private_key_;
@ -2588,7 +2572,8 @@ struct ToRawTransactions {
}
}
if (!data) {
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)), to_bytes(std::move(init_state_cell)));
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)),
to_bytes(std::move(init_state_cell)));
}
return data;
};
@ -2636,7 +2621,8 @@ struct ToRawTransactions {
auto created_lt = static_cast<td::int64>(msg_info.created_lt);
return tonlib_api::make_object<tonlib_api::raw_message>(
tonlib_api::make_object<tonlib_api::accountAddress>(src),
tonlib_api::make_object<tonlib_api::accountAddress>(), 0, 0, 0, created_lt, std::move(body_hash), get_data(src));
tonlib_api::make_object<tonlib_api::accountAddress>(), 0, 0, 0, created_lt, std::move(body_hash),
get_data(src));
}
}
@ -2746,10 +2732,9 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_sendMessageReturnHash&
td::Promise<object_ptr<tonlib_api::raw_extMessageInfo>>&& promise) {
TRY_RESULT_PREFIX(body, vm::std_boc_deserialize(request.body_), TonlibError::InvalidBagOfCells("body"));
auto hash = body->get_hash().as_slice().str();
make_request(int_api::SendMessage{std::move(body)},
promise.wrap([hash = std::move(hash)](auto res) {
return tonlib_api::make_object<tonlib_api::raw_extMessageInfo>(std::move(hash));
}));
make_request(int_api::SendMessage{std::move(body)}, promise.wrap([hash = std::move(hash)](auto res) {
return tonlib_api::make_object<tonlib_api::raw_extMessageInfo>(std::move(hash));
}));
return td::Status::OK();
}
@ -2839,7 +2824,7 @@ td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request,
}
td::Status TonlibClient::do_request(tonlib_api::raw_getTransactionsV2& request,
td::Promise<object_ptr<tonlib_api::raw_transactions>>&& promise) {
td::Promise<object_ptr<tonlib_api::raw_transactions>>&& promise) {
if (!request.account_address_) {
return TonlibError::EmptyField("account_address");
}
@ -2875,9 +2860,10 @@ td::Status TonlibClient::do_request(tonlib_api::raw_getTransactionsV2& request,
auto actor_id = actor_id_++;
actors_[actor_id] = td::actor::create_actor<GetTransactionHistory>(
"GetTransactionHistory", client_.get_client(), account_address, lt, hash, count, actor_shared(this, actor_id),
promise.wrap([private_key = std::move(private_key), try_decode_messages = request.try_decode_messages_](auto&& x) mutable {
return ToRawTransactions(std::move(private_key), try_decode_messages).to_raw_transactions(std::move(x));
}));
promise.wrap(
[private_key = std::move(private_key), try_decode_messages = request.try_decode_messages_](auto&& x) mutable {
return ToRawTransactions(std::move(private_key), try_decode_messages).to_raw_transactions(std::move(x));
}));
return td::Status::OK();
}
@ -3044,26 +3030,25 @@ class GenericCreateSendGrams : public TonlibQueryActor {
td::Result<ton::ManualDns::Action> to_dns_action(tonlib_api::dns_Action& action) {
using R = td::Result<ton::ManualDns::Action>;
return downcast_call2<R>(action,
td::overloaded(
[&](tonlib_api::dns_actionDeleteAll& del_all) -> R {
return ton::ManualDns::Action{"", td::Bits256::zero(), {}};
},
[&](tonlib_api::dns_actionDelete& del) -> R {
return ton::ManualDns::Action{del.name_, del.category_, {}};
},
[&](tonlib_api::dns_actionSet& set) -> R {
if (!set.entry_) {
return TonlibError::EmptyField("entry");
}
if (!set.entry_->entry_) {
return TonlibError::EmptyField("entry.entry");
}
TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_));
TRY_RESULT(data_cell, entry_data.as_cell());
return ton::ManualDns::Action{set.entry_->name_, set.entry_->category_,
std::move(data_cell)};
}));
return downcast_call2<R>(
action, td::overloaded(
[&](tonlib_api::dns_actionDeleteAll& del_all) -> R {
return ton::ManualDns::Action{"", td::Bits256::zero(), {}};
},
[&](tonlib_api::dns_actionDelete& del) -> R {
return ton::ManualDns::Action{del.name_, del.category_, {}};
},
[&](tonlib_api::dns_actionSet& set) -> R {
if (!set.entry_) {
return TonlibError::EmptyField("entry");
}
if (!set.entry_->entry_) {
return TonlibError::EmptyField("entry.entry");
}
TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_));
TRY_RESULT(data_cell, entry_data.as_cell());
return ton::ManualDns::Action{set.entry_->name_, set.entry_->category_, std::move(data_cell)};
}));
}
td::Status parse_action(tonlib_api::Action& action) {
@ -3471,9 +3456,9 @@ class GenericCreateSendGrams : public TonlibQueryActor {
}
}
// if (!o_public_key) { // todo: (tolya-yanot) temporary disable msg comment encryption (The exchanges/payment services needs to read the comment of incoming messages). This will be uncommented when a general standard is developed.
return TonlibError::MessageEncryption("Get public key (in destination)");
// }
// if (!o_public_key) { // todo: (tolya-yanot) temporary disable msg comment encryption (The exchanges/payment services needs to read the comment of incoming messages). This will be uncommented when a general standard is developed.
return TonlibError::MessageEncryption("Get public key (in destination)");
// }
auto addr = source_->get_address();
addr.bounceable = true;
@ -3868,8 +3853,8 @@ td::Result<vm::StackEntry> from_tonlib_api(tonlib_api::tvm_StackEntry& entry) {
}));
}
void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& visited,
vm::Dictionary& libs, td::Ref<vm::Cell> cell, int depth) {
void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& visited, vm::Dictionary& libs,
td::Ref<vm::Cell> cell, int depth) {
if (depth <= 0 || set.size() >= 16 || visited.size() >= 256) {
return;
}
@ -3895,7 +3880,7 @@ void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& v
}
return;
}
for (unsigned int i=0; i<loaded_cell.data_cell->get_refs_cnt(); i++) {
for (unsigned int i = 0; i < loaded_cell.data_cell->get_refs_cnt(); i++) {
deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1);
}
}
@ -3919,36 +3904,38 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getLibraries& request,
return td::Status::OK();
}
client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(not_cached_hashes)),
promise.wrap([self=this, result_entries = std::move(result_entries)]
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
{
if (r_libraries.is_error()) {
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
} else {
auto libraries = r_libraries.move_as_ok();
bool updated = false;
for (auto& lr : libraries->result_) {
auto contents = vm::std_boc_deserialize(lr->data_);
if (contents.is_ok() && contents.ok().not_null()) {
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
continue;
client_.send_query(
ton::lite_api::liteServer_getLibraries(std::move(not_cached_hashes)),
promise.wrap(
[self = this, result_entries = std::move(result_entries)](
td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable {
if (r_libraries.is_error()) {
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
} else {
auto libraries = r_libraries.move_as_ok();
bool updated = false;
for (auto& lr : libraries->result_) {
auto contents = vm::std_boc_deserialize(lr->data_);
if (contents.is_ok() && contents.ok().not_null()) {
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
continue;
}
result_entries.push_back(
tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lr->hash_, lr->data_.as_slice().str()));
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
updated = true;
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
} else {
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
}
if (updated) {
self->store_libs_to_disk();
}
}
}
result_entries.push_back(tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lr->hash_, lr->data_.as_slice().str()));
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
updated = true;
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
} else {
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
}
if (updated) {
self->store_libs_to_disk();
}
}
}
return tonlib_api::make_object<tonlib_api::smc_libraryResult>(std::move(result_entries));
}));
return tonlib_api::make_object<tonlib_api::smc_libraryResult>(std::move(result_entries));
}));
return td::Status::OK();
}
@ -3975,8 +3962,8 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
args.set_now(it->second->get_sync_time());
args.set_address(it->second->get_address());
client_.with_last_config([self = this, smc = std::move(smc), args = std::move(args), promise = std::move(promise)
](td::Result<LastConfigState> r_state) mutable {
client_.with_last_config([self = this, smc = std::move(smc), args = std::move(args),
promise = std::move(promise)](td::Result<LastConfigState> r_state) mutable {
TRY_RESULT_PROMISE(promise, state, std::move(r_state));
args.set_config(state.config);
@ -3988,41 +3975,39 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
std::vector<td::Bits256> libraryList{librarySet.begin(), librarySet.end()};
if (libraryList.size() > 0) {
LOG(DEBUG) << "Requesting found libraries in code (" << libraryList.size() << ")";
self->client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(libraryList)),
[self, smc = std::move(smc), args = std::move(args), promise = std::move(promise)]
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
{
if (r_libraries.is_error()) {
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
} else {
auto libraries = r_libraries.move_as_ok();
bool updated = false;
for (auto& lr : libraries->result_) {
auto contents = vm::std_boc_deserialize(lr->data_);
if (contents.is_ok() && contents.ok().not_null()) {
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
continue;
}
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
updated = true;
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
self->client_.send_query(
ton::lite_api::liteServer_getLibraries(std::move(libraryList)),
[self, smc = std::move(smc), args = std::move(args), promise = std::move(promise)](
td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable {
if (r_libraries.is_error()) {
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
} else {
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
auto libraries = r_libraries.move_as_ok();
bool updated = false;
for (auto& lr : libraries->result_) {
auto contents = vm::std_boc_deserialize(lr->data_);
if (contents.is_ok() && contents.ok().not_null()) {
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
continue;
}
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
updated = true;
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
} else {
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
}
}
if (updated) {
self->store_libs_to_disk();
}
}
}
if (updated) {
self->store_libs_to_disk();
}
}
self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
});
}
else {
self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
});
} else {
self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
}
}
else {
} else {
self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
}
});
@ -4031,7 +4016,6 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::SmartContract::Args args,
td::Promise<object_ptr<tonlib_api::smc_runResult>>&& promise) {
args.set_libraries(libraries);
auto res = smc->run_get_method(args);
@ -4046,45 +4030,46 @@ void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::S
td::Bits256 hash = res.missing_library;
LOG(DEBUG) << "Requesting missing library: " << hash.to_hex();
std::vector<td::Bits256> req = {std::move(hash)};
client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(req)),
[self = this, res = std::move(res), res_stack = std::move(res_stack), hash = std::move(hash),
smc = std::move(smc), args = std::move(args), promise = std::move(promise)]
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
{
if (r_libraries.is_error()) {
LOG(WARNING) << "cannot obtain missing library: " << r_libraries.move_as_error().to_string();
promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
return;
}
bool found = false, updated = false;
auto libraries = r_libraries.move_as_ok();
for (auto& lr : libraries->result_) {
auto contents = vm::std_boc_deserialize(lr->data_);
if (contents.is_ok() && contents.ok().not_null()) {
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
continue;
client_.send_query(
ton::lite_api::liteServer_getLibraries(std::move(req)),
[self = this, res = std::move(res), res_stack = std::move(res_stack), hash = std::move(hash),
smc = std::move(smc), args = std::move(args), promise = std::move(promise)](
td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable {
if (r_libraries.is_error()) {
LOG(WARNING) << "cannot obtain missing library: " << r_libraries.move_as_error().to_string();
promise.set_value(
tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
return;
}
found |= (lr->hash_ == hash);
updated = true;
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
} else {
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
}
}
if (updated) {
self->store_libs_to_disk();
}
if (!found) {
LOG(WARNING) << "cannot obtain library " << hash.to_hex() << ", it may not exist";
promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
} else {
self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
}
});
}
else {
bool found = false, updated = false;
auto libraries = r_libraries.move_as_ok();
for (auto& lr : libraries->result_) {
auto contents = vm::std_boc_deserialize(lr->data_);
if (contents.is_ok() && contents.ok().not_null()) {
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
continue;
}
found |= (lr->hash_ == hash);
updated = true;
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
} else {
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
}
}
if (updated) {
self->store_libs_to_disk();
}
if (!found) {
LOG(WARNING) << "cannot obtain library " << hash.to_hex() << ", it may not exist";
promise.set_value(
tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
} else {
self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
}
});
} else {
promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
}
}
@ -4160,9 +4145,8 @@ void TonlibClient::do_dns_request(std::string name, td::Bits256 category, td::in
td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
auto block_id_copy = block_id.copy();
td::Promise<DnsFinishData> new_promise =
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id),
address);
td::Promise<DnsFinishData> new_promise = promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name,
category, ttl, std::move(block_id), address);
if (0) {
make_request(int_api::GetAccountState{address, std::move(block_id_copy), {}},
@ -4200,8 +4184,7 @@ td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
name += '.';
}
TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_));
do_dns_request(name, request.category_, request.ttl_, std::move(block_id), account_address,
std::move(promise));
do_dns_request(name, request.category_, request.ttl_, std::move(block_id), account_address, std::move(promise));
return td::Status::OK();
}
@ -4639,15 +4622,15 @@ auto to_tonlib_api(const ton::lite_api::tonNode_blockIdExt& blk) -> tonlib_api_p
auto to_tonlib_api(const ton::lite_api::tonNode_zeroStateIdExt& zeroStateId)
-> tonlib_api_ptr<tonlib_api::ton_blockIdExt> {
return tonlib_api::make_object<tonlib_api::ton_blockIdExt>( //TODO check wether shard indeed 0???
return tonlib_api::make_object<tonlib_api::ton_blockIdExt>( //TODO check wether shard indeed 0???
zeroStateId.workchain_, 0, 0, zeroStateId.root_hash_.as_slice().str(), zeroStateId.file_hash_.as_slice().str());
}
auto to_lite_api(const tonlib_api::ton_blockIdExt& blk) -> td::Result<lite_api_ptr<ton::lite_api::tonNode_blockIdExt>> {
TRY_RESULT(root_hash, to_bits256(blk.root_hash_, "blk.root_hash"))
TRY_RESULT(file_hash, to_bits256(blk.file_hash_, "blk.file_hash"))
return ton::lite_api::make_object<ton::lite_api::tonNode_blockIdExt>(
blk.workchain_, blk.shard_, blk.seqno_, root_hash, file_hash);
return ton::lite_api::make_object<ton::lite_api::tonNode_blockIdExt>(blk.workchain_, blk.shard_, blk.seqno_,
root_hash, file_hash);
}
td::Result<ton::BlockIdExt> to_block_id(const tonlib_api::ton_blockIdExt& blk) {
@ -4657,33 +4640,34 @@ td::Result<ton::BlockIdExt> to_block_id(const tonlib_api::ton_blockIdExt& blk) {
}
td::Status TonlibClient::do_request(const tonlib_api::getConfigParam& request,
td::Promise<object_ptr<tonlib_api::configInfo>>&& promise) {
td::Promise<object_ptr<tonlib_api::configInfo>>&& promise) {
TRY_RESULT(lite_block, to_lite_api(*request.id_))
auto block = create_block_id(std::move(lite_block));
auto param = request.param_;
std::vector<int32_t> params = { param };
std::vector<int32_t> params = {param};
client_.send_query(ton::lite_api::liteServer_getConfigParams(0, std::move(lite_block), std::move(params)),
promise.wrap([block, param](auto r_config) {
auto state = block::check_extract_state_proof(block, r_config->state_proof_.as_slice(),
r_config->config_proof_.as_slice());
if (state.is_error()) {
LOG(ERROR) << "block::check_extract_state_proof failed: " << state.error();
}
auto config = block::Config::extract_from_state(std::move(state.move_as_ok()), 0);
if (config.is_error()) {
LOG(ERROR) << "block::Config::extract_from_state failed: " << config.error();
}
tonlib_api::configInfo config_result;
config_result.config_ = tonlib_api::make_object<tonlib_api::tvm_cell>(to_bytes(config.move_as_ok()->get_config_param(param)));
return tonlib_api::make_object<tonlib_api::configInfo>(std::move(config_result));
}));
auto state = block::check_extract_state_proof(block, r_config->state_proof_.as_slice(),
r_config->config_proof_.as_slice());
if (state.is_error()) {
LOG(ERROR) << "block::check_extract_state_proof failed: " << state.error();
}
auto config = block::Config::extract_from_state(std::move(state.move_as_ok()), 0);
if (config.is_error()) {
LOG(ERROR) << "block::Config::extract_from_state failed: " << config.error();
}
tonlib_api::configInfo config_result;
config_result.config_ = tonlib_api::make_object<tonlib_api::tvm_cell>(
to_bytes(config.move_as_ok()->get_config_param(param)));
return tonlib_api::make_object<tonlib_api::configInfo>(std::move(config_result));
}));
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::blocks_getMasterchainInfo& masterchain_info,
td::Promise<object_ptr<tonlib_api::blocks_masterchainInfo>>&& promise) {
td::Promise<object_ptr<tonlib_api::blocks_masterchainInfo>>&& promise) {
client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_masterchainInfo>&& masterchain_info) {
return tonlib_api::make_object<tonlib_api::blocks_masterchainInfo>(
@ -4728,133 +4712,126 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getShards& request,
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& request,
td::Promise<object_ptr<tonlib_api::ton_blockIdExt>>&& promise) {
td::Promise<object_ptr<tonlib_api::ton_blockIdExt>>&& promise) {
client_.send_query(ton::lite_api::liteServer_lookupBlock(
request.mode_,
ton::lite_api::make_object<ton::lite_api::tonNode_blockId>((*request.id_).workchain_, (*request.id_).shard_, (*request.id_).seqno_),
(td::uint64)(request.lt_),
(td::uint32)(request.utime_)),
request.mode_,
ton::lite_api::make_object<ton::lite_api::tonNode_blockId>(
(*request.id_).workchain_, (*request.id_).shard_, (*request.id_).seqno_),
(td::uint64)(request.lt_), (td::uint32)(request.utime_)),
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& header) {
const auto& id = header->id_;
return to_tonlib_api(*id);
//tonlib_api::make_object<tonlib_api::ton_blockIdExt>(
// ton::tonlib_api::ton_blockIdExt(id->workchain_, id->)
//);
const auto& id = header->id_;
return to_tonlib_api(*id);
//tonlib_api::make_object<tonlib_api::ton_blockIdExt>(
// ton::tonlib_api::ton_blockIdExt(id->workchain_, id->)
//);
}));
return td::Status::OK();
}
auto to_tonlib_api(const ton::lite_api::liteServer_transactionId& txid)
-> tonlib_api_ptr<tonlib_api::blocks_shortTxId> {
return tonlib_api::make_object<tonlib_api::blocks_shortTxId>(
txid.mode_, txid.account_.as_slice().str(), txid.lt_, txid.hash_.as_slice().str());
return tonlib_api::make_object<tonlib_api::blocks_shortTxId>(txid.mode_, txid.account_.as_slice().str(), txid.lt_,
txid.hash_.as_slice().str());
}
td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& request,
td::Promise<object_ptr<tonlib_api::blocks_transactions>>&& promise) {
td::Promise<object_ptr<tonlib_api::blocks_transactions>>&& promise) {
TRY_RESULT(block, to_lite_api(*request.id_))
TRY_RESULT(account, to_bits256((*request.after_).account_, "account"));
auto after = ton::lite_api::make_object<ton::lite_api::liteServer_transactionId3>(account, (*request.after_).lt_);
client_.send_query(ton::lite_api::liteServer_listBlockTransactions(
std::move(block),
request.mode_,
request.count_,
std::move(after),
false,
false),
client_.send_query(ton::lite_api::liteServer_listBlockTransactions(std::move(block), request.mode_, request.count_,
std::move(after), false, false),
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockTransactions>&& bTxes) {
const auto& id = bTxes->id_;
//for (auto id : ids) {
tonlib_api::blocks_transactions r;
r.id_ = to_tonlib_api(*id);
r.req_count_ = bTxes->req_count_;
r.incomplete_ = bTxes->incomplete_;
for (auto& id: bTxes->ids_) {
//tonlib_api::blocks_shortTxId txid = tonlib_api::blocks_shortTxId(id->mode_, id->account_.as_slice().str(), id->lt_, id->hash_.as_slice().str());
//r.transactions_.push_back(txid);
r.transactions_.push_back(to_tonlib_api(*id));
}
return tonlib_api::make_object<tonlib_api::blocks_transactions>(std::move(r));
const auto& id = bTxes->id_;
//for (auto id : ids) {
tonlib_api::blocks_transactions r;
r.id_ = to_tonlib_api(*id);
r.req_count_ = bTxes->req_count_;
r.incomplete_ = bTxes->incomplete_;
for (auto& id : bTxes->ids_) {
//tonlib_api::blocks_shortTxId txid = tonlib_api::blocks_shortTxId(id->mode_, id->account_.as_slice().str(), id->lt_, id->hash_.as_slice().str());
//r.transactions_.push_back(txid);
r.transactions_.push_back(to_tonlib_api(*id));
}
return tonlib_api::make_object<tonlib_api::blocks_transactions>(std::move(r));
}));
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::blocks_getBlockHeader& request,
td::Promise<object_ptr<tonlib_api::blocks_header>>&& promise) {
td::Promise<object_ptr<tonlib_api::blocks_header>>&& promise) {
TRY_RESULT(block, to_lite_api(*request.id_))
client_.send_query(ton::lite_api::liteServer_getBlockHeader(
std::move(block),
0xffff),
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& hdr) {
auto blk_id = ton::create_block_id(hdr->id_);
auto R = vm::std_boc_deserialize(std::move(hdr->header_proof_));
tonlib_api::blocks_header header;
if (R.is_error()) {
LOG(WARNING) << "R.is_error() ";
} else {
auto root = R.move_as_ok();
try {
ton::RootHash vhash{root->get_hash().bits()};
auto virt_root = vm::MerkleProof::virtualize(root, 1);
if (virt_root.is_null()) {
LOG(WARNING) << "virt root is null";
} else {
std::vector<ton::BlockIdExt> prev;
ton::BlockIdExt mc_blkid;
bool after_split;
auto res = block::unpack_block_prev_blk_ext(virt_root, blk_id, prev, mc_blkid, after_split);
if (res.is_error()) {
LOG(WARNING) << "res.is_error() ";
} else {
block::gen::Block::Record blk;
block::gen::BlockInfo::Record info;
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info))) {
LOG(WARNING) << "unpack failed";
} else {
header.id_ = to_tonlib_api(blk_id);
header.global_id_ = blk.global_id;
header.version_ = info.version;
header.flags_ = info.flags;
header.after_merge_ = info.after_merge;
header.after_split_ = info.after_split;
header.before_split_ = info.before_split;
header.want_merge_ = info.want_merge;
header.want_split_ = info.want_split;
header.validator_list_hash_short_ = info.gen_validator_list_hash_short;
header.catchain_seqno_ = info.gen_catchain_seqno;
header.min_ref_mc_seqno_ = info.min_ref_mc_seqno;
header.start_lt_ = info.start_lt;
header.end_lt_ = info.end_lt;
header.gen_utime_ = info.gen_utime;
header.is_key_block_ = info.key_block;
header.vert_seqno_ = info.vert_seq_no;
if(!info.not_master) {
header.prev_key_block_seqno_ = info.prev_key_block_seqno;
}
for (auto id : prev) {
header.prev_blocks_.push_back(to_tonlib_api(id));
}
//if(info.before_split) {
//} else {
//}
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
}
}
}
} catch (vm::VmError& err) {
auto E = err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
LOG(ERROR) << std::move(E);
} catch (vm::VmVirtError& err) {
auto E = err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
LOG(ERROR) << std::move(E);
} catch (...) {
LOG(WARNING) << "exception catched ";
}
}
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
}));
client_.send_query(
ton::lite_api::liteServer_getBlockHeader(std::move(block), 0xffff),
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& hdr) {
auto blk_id = ton::create_block_id(hdr->id_);
auto R = vm::std_boc_deserialize(std::move(hdr->header_proof_));
tonlib_api::blocks_header header;
if (R.is_error()) {
LOG(WARNING) << "R.is_error() ";
} else {
auto root = R.move_as_ok();
try {
ton::RootHash vhash{root->get_hash().bits()};
auto virt_root = vm::MerkleProof::virtualize(root, 1);
if (virt_root.is_null()) {
LOG(WARNING) << "virt root is null";
} else {
std::vector<ton::BlockIdExt> prev;
ton::BlockIdExt mc_blkid;
bool after_split;
auto res = block::unpack_block_prev_blk_ext(virt_root, blk_id, prev, mc_blkid, after_split);
if (res.is_error()) {
LOG(WARNING) << "res.is_error() ";
} else {
block::gen::Block::Record blk;
block::gen::BlockInfo::Record info;
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info))) {
LOG(WARNING) << "unpack failed";
} else {
header.id_ = to_tonlib_api(blk_id);
header.global_id_ = blk.global_id;
header.version_ = info.version;
header.flags_ = info.flags;
header.after_merge_ = info.after_merge;
header.after_split_ = info.after_split;
header.before_split_ = info.before_split;
header.want_merge_ = info.want_merge;
header.want_split_ = info.want_split;
header.validator_list_hash_short_ = info.gen_validator_list_hash_short;
header.catchain_seqno_ = info.gen_catchain_seqno;
header.min_ref_mc_seqno_ = info.min_ref_mc_seqno;
header.start_lt_ = info.start_lt;
header.end_lt_ = info.end_lt;
header.gen_utime_ = info.gen_utime;
header.is_key_block_ = info.key_block;
header.vert_seqno_ = info.vert_seq_no;
if (!info.not_master) {
header.prev_key_block_seqno_ = info.prev_key_block_seqno;
}
for (auto id : prev) {
header.prev_blocks_.push_back(to_tonlib_api(id));
}
//if(info.before_split) {
//} else {
//}
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
}
}
}
} catch (vm::VmError& err) {
auto E = err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
LOG(ERROR) << std::move(E);
} catch (vm::VmVirtError& err) {
auto E = err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
LOG(ERROR) << std::move(E);
} catch (...) {
LOG(WARNING) << "exception catched ";
}
}
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
}));
return td::Status::OK();
}
@ -4890,15 +4867,17 @@ void TonlibClient::load_libs_from_disk() {
if (r_dict.is_error()) {
return;
}
libraries = vm::Dictionary(vm::load_cell_slice(vm::CellBuilder().append_cellslice(vm::load_cell_slice(
r_dict.move_as_ok())).finalize()), 256);
libraries = vm::Dictionary(
vm::load_cell_slice(vm::CellBuilder().append_cellslice(vm::load_cell_slice(r_dict.move_as_ok())).finalize()),
256);
// int n = 0; for (auto&& lr : libraries) n++;
LOG(DEBUG) << "loaded libraries from disk cache";
}
void TonlibClient::store_libs_to_disk() { // NB: Dictionary.get_root_cell does not compute_root, and it is protected
kv_->set("tonlib.libcache", vm::std_boc_serialize(vm::CellBuilder().append_cellslice(libraries.get_root())
.finalize()).move_as_ok().as_slice());
kv_->set("tonlib.libcache", vm::std_boc_serialize(vm::CellBuilder().append_cellslice(libraries.get_root()).finalize())
.move_as_ok()
.as_slice());
// int n = 0; for (auto&& lr : libraries) n++;
LOG(DEBUG) << "stored libraries to disk cache";
}

View file

@ -47,7 +47,7 @@
#include "tonlib/TonlibClient.h"
#include "tonlib/TonlibCallback.h"
#include "tonlib/ExtClientRaw.h"
#include "tonlib/ExtClientLazy.h"
#include "smc-envelope/ManualDns.h"
#include "smc-envelope/PaymentChannel.h"
@ -62,7 +62,6 @@
#include <iostream>
#include <map>
#include "git.h"
#include "ExtClientMulti.h"
using tonlib_api::make_object;
@ -224,7 +223,7 @@ class TonlibCli : public td::actor::Actor {
if (options_.use_callbacks_for_network) {
auto config = tonlib::Config::parse(options_.config).move_as_ok();
class Callback : public tonlib::ExtClientRaw::Callback {
class Callback : public tonlib::ExtClientLazy::Callback {
public:
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
}
@ -232,28 +231,15 @@ class TonlibCli : public td::actor::Actor {
private:
td::actor::ActorShared<> parent_;
};
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> full_servers;
int lite_client_id = -1, cnt = 0;
for (const auto& s : config.lite_clients) {
if (s.is_full) {
full_servers.emplace_back(s.adnl_id, s.address);
}
}
if (!full_servers.empty()) {
raw_client_ = tonlib::ExtClientRaw::create(std::move(full_servers),
td::make_unique<Callback>(td::actor::actor_shared()));
} else {
CHECK(!config.lite_clients.empty());
raw_client_ = td::actor::create_actor<tonlib::ExtClientMulti>(
"ExtClientMulti", config.lite_clients, td::make_unique<Callback>(td::actor::actor_shared()));
}
ref_cnt_++;
raw_client_ = tonlib::ExtClientLazy::create(config.lite_servers,
td::make_unique<Callback>(td::actor::actor_shared()));
}
auto config = !options_.config.empty()
? make_object<tonlib_api::config>(options_.config, options_.name,
options_.use_callbacks_for_network, options_.ignore_cache)
: nullptr;
? make_object<tonlib_api::config>(options_.config, options_.name,
options_.use_callbacks_for_network, options_.ignore_cache)
: nullptr;
tonlib_api::object_ptr<tonlib_api::KeyStoreType> ks_type;
if (options_.in_memory) {
@ -1544,9 +1530,8 @@ class TonlibCli : public td::actor::Actor {
auto update = tonlib_api::move_object_as<tonlib_api::updateSendLiteServerQuery>(std::move(result));
CHECK(!raw_client_.empty());
snd_bytes_ += update->data_.size();
ton::ShardIdFull shard(update->workchain_, update->shard_);
send_closure(raw_client_, &tonlib::ExtClientRaw::send_query, "query", td::BufferSlice(update->data_), shard,
td::Timestamp::in(5),
send_closure(raw_client_, &tonlib::ExtClientLazy::send_query, "query", td::BufferSlice(update->data_),
ton::ShardIdFull(update->workchain_, update->shard_), td::Timestamp::in(5),
[actor_id = actor_id(this), id = update->id_](td::Result<td::BufferSlice> res) {
send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res));
});