2
This file is part of TON Blockchain Library.
4
TON Blockchain Library is free software: you can redistribute it and/or modify
5
it under the terms of the GNU Lesser General Public License as published by
6
the Free Software Foundation, either version 2 of the License, or
7
(at your option) any later version.
9
TON Blockchain Library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
17
Copyright 2017-2020 Telegram Systems LLP
19
#include "download-state.hpp"
20
#include "ton/ton-tl.hpp"
21
#include "ton/ton-io.hpp"
22
#include "td/utils/overloaded.h"
31
DownloadState::DownloadState(BlockIdExt block_id, BlockIdExt masterchain_block_id, adnl::AdnlNodeIdShort local_id,
32
overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from,
33
td::uint32 priority, td::Timestamp timeout,
34
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
35
td::actor::ActorId<adnl::AdnlSenderInterface> rldp,
36
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<adnl::Adnl> adnl,
37
td::actor::ActorId<adnl::AdnlExtClient> client, td::Promise<td::BufferSlice> promise)
39
, masterchain_block_id_(masterchain_block_id)
41
, overlay_id_(overlay_id)
42
, download_from_(download_from)
45
, validator_manager_(validator_manager)
50
, promise_(std::move(promise)) {
53
void DownloadState::abort_query(td::Status reason) {
55
if (reason.code() == ErrorCode::notready || reason.code() == ErrorCode::timeout) {
56
VLOG(FULL_NODE_DEBUG) << "failed to download state " << block_id_ << " from " << download_from_ << ": " << reason;
58
VLOG(FULL_NODE_NOTICE) << "failed to download state " << block_id_ << " from " << download_from_ << ": "
61
promise_.set_error(std::move(reason));
66
void DownloadState::alarm() {
67
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
70
void DownloadState::finish_query() {
72
promise_.set_value(std::move(state_));
77
void DownloadState::start_up() {
78
alarm_timestamp() = timeout_;
80
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
82
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
84
td::actor::send_closure(SelfId, &DownloadState::got_block_handle, R.move_as_ok());
88
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle, block_id_, true,
92
void DownloadState::got_block_handle(BlockHandle handle) {
93
handle_ = std::move(handle);
94
if (!download_from_.is_zero() || !client_.empty()) {
95
got_node_to_download(download_from_);
97
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::vector<adnl::AdnlNodeIdShort>> R) {
99
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
101
auto vec = R.move_as_ok();
102
if (vec.size() == 0) {
103
td::actor::send_closure(SelfId, &DownloadState::abort_query,
104
td::Status::Error(ErrorCode::notready, "no nodes"));
106
td::actor::send_closure(SelfId, &DownloadState::got_node_to_download, vec[0]);
111
td::actor::send_closure(overlays_, &overlay::Overlays::get_overlay_random_peers, local_id_, overlay_id_, 1,
116
void DownloadState::got_node_to_download(adnl::AdnlNodeIdShort node) {
117
download_from_ = node;
118
LOG(INFO) << "downloading state " << block_id_.to_str() << " from " << download_from_;
120
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) mutable {
122
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
124
td::actor::send_closure(SelfId, &DownloadState::got_block_state_description, R.move_as_ok());
128
td::BufferSlice query;
129
if (masterchain_block_id_.is_valid()) {
130
query = create_serialize_tl_object<ton_api::tonNode_preparePersistentState>(
131
create_tl_block_id(block_id_), create_tl_block_id(masterchain_block_id_));
133
query = create_serialize_tl_object<ton_api::tonNode_prepareZeroState>(create_tl_block_id(block_id_));
136
if (client_.empty()) {
137
td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_,
138
"get_prepare", std::move(P), td::Timestamp::in(1.0), std::move(query));
140
td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare",
141
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(query)),
142
td::Timestamp::in(1.0), std::move(P));
146
void DownloadState::got_block_state_description(td::BufferSlice data) {
147
auto F = fetch_tl_object<ton_api::tonNode_PreparedState>(std::move(data), true);
149
abort_query(F.move_as_error());
152
prev_logged_timer_ = td::Timer();
154
ton_api::downcast_call(
155
*F.move_as_ok().get(),
157
[&](ton_api::tonNode_notFoundState &f) {
158
abort_query(td::Status::Error(ErrorCode::notready, "state not found"));
160
[&, self = this](ton_api::tonNode_preparedState &f) {
161
if (masterchain_block_id_.is_valid()) {
162
got_block_state_part(td::BufferSlice{}, 0);
165
auto P = td::PromiseCreator::lambda([SelfId = actor_id(self)](td::Result<td::BufferSlice> R) {
167
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
169
td::actor::send_closure(SelfId, &DownloadState::got_block_state, R.move_as_ok());
173
td::BufferSlice query =
174
create_serialize_tl_object<ton_api::tonNode_downloadZeroState>(create_tl_block_id(block_id_));
175
if (client_.empty()) {
176
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_,
177
overlay_id_, "download state", std::move(P), td::Timestamp::in(3.0),
178
std::move(query), FullNode::max_state_size(), rldp_);
180
td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download state",
181
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(query)),
182
td::Timestamp::in(3.0), std::move(P));
187
void DownloadState::got_block_state_part(td::BufferSlice data, td::uint32 requested_size) {
188
bool last_part = data.size() < requested_size;
190
parts_.push_back(std::move(data));
192
double elapsed = prev_logged_timer_.elapsed();
193
if (elapsed > 10.0) {
194
prev_logged_timer_ = td::Timer();
195
LOG(INFO) << "downloading state " << block_id_.to_str() << ": total=" << sum_ << " ("
196
<< td::format::as_size((td::uint64)(double(sum_ - prev_logged_sum_) / elapsed)) << "/s)";
197
prev_logged_sum_ = sum_;
201
td::BufferSlice res{td::narrow_cast<std::size_t>(sum_)};
202
auto S = res.as_slice();
203
for (auto &p : parts_) {
204
S.copy_from(p.as_slice());
205
S.remove_prefix(p.size());
209
got_block_state(std::move(res));
213
td::uint32 part_size = 1 << 21;
214
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), part_size](td::Result<td::BufferSlice> R) {
216
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
218
td::actor::send_closure(SelfId, &DownloadState::got_block_state_part, R.move_as_ok(), part_size);
222
td::BufferSlice query = create_serialize_tl_object<ton_api::tonNode_downloadPersistentStateSlice>(
223
create_tl_block_id(block_id_), create_tl_block_id(masterchain_block_id_), sum_, part_size);
224
if (client_.empty()) {
225
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_,
226
"download state", std::move(P), td::Timestamp::in(20.0), std::move(query),
227
FullNode::max_state_size(), rldp_);
229
td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download state",
230
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(query)),
231
td::Timestamp::in(20.0), std::move(P));
235
void DownloadState::got_block_state(td::BufferSlice data) {
236
state_ = std::move(data);
237
LOG(INFO) << "finished downloading state " << block_id_.to_str() << ": total=" << sum_;
241
} // namespace fullnode
243
} // namespace validator