Ton

Форк
0
/
download-block-new.cpp 
286 строк · 10.9 Кб
1
/*
2
    This file is part of TON Blockchain Library.
3

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.
8

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.
13

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/>.
16

17
    Copyright 2017-2020 Telegram Systems LLP
18
*/
19
#include "download-block-new.hpp"
20
#include "ton/ton-tl.hpp"
21
#include "adnl/utils.hpp"
22
#include "ton/ton-shard.h"
23
#include "td/utils/overloaded.h"
24
#include "ton/ton-io.hpp"
25
#include "validator/full-node.h"
26
#include "full-node-serializer.hpp"
27

28
namespace ton {
29

30
namespace validator {
31

32
namespace fullnode {
33

34
DownloadBlockNew::DownloadBlockNew(BlockIdExt block_id, adnl::AdnlNodeIdShort local_id,
35
                                   overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from,
36
                                   td::uint32 priority, td::Timestamp timeout,
37
                                   td::actor::ActorId<ValidatorManagerInterface> validator_manager,
38
                                   td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
39
                                   td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<adnl::AdnlExtClient> client,
40
                                   td::Promise<ReceivedBlock> promise)
41
    : block_id_(block_id)
42
    , local_id_(local_id)
43
    , overlay_id_(overlay_id)
44
    , download_from_(download_from)
45
    , priority_(priority)
46
    , timeout_(timeout)
47
    , validator_manager_(validator_manager)
48
    , rldp_(rldp)
49
    , overlays_(overlays)
50
    , adnl_(adnl)
51
    , client_(client)
52
    , promise_(std::move(promise))
53
    , block_{block_id_, td::BufferSlice()}
54
    , allow_partial_proof_{!block_id_.is_masterchain()} {
55
}
56

57
DownloadBlockNew::DownloadBlockNew(adnl::AdnlNodeIdShort local_id, overlay::OverlayIdShort overlay_id,
58
                                   BlockIdExt prev_id, adnl::AdnlNodeIdShort download_from, td::uint32 priority,
59
                                   td::Timestamp timeout,
60
                                   td::actor::ActorId<ValidatorManagerInterface> validator_manager,
61
                                   td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
62
                                   td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<adnl::AdnlExtClient> client,
63
                                   td::Promise<ReceivedBlock> promise)
64
    : local_id_(local_id)
65
    , overlay_id_(overlay_id)
66
    , prev_id_(prev_id)
67
    , download_from_(download_from)
68
    , priority_(priority)
69
    , timeout_(timeout)
70
    , validator_manager_(validator_manager)
71
    , rldp_(rldp)
72
    , overlays_(overlays)
73
    , adnl_(adnl)
74
    , client_(client)
75
    , promise_(std::move(promise))
76
    , block_{BlockIdExt{}, td::BufferSlice()} {
77
}
78

79
void DownloadBlockNew::abort_query(td::Status reason) {
80
  if (promise_) {
81
    if (reason.code() == ErrorCode::notready || reason.code() == ErrorCode::timeout) {
82
      VLOG(FULL_NODE_DEBUG) << "failed to download block " << block_id_ << "from " << download_from_ << ": " << reason;
83
    } else {
84
      VLOG(FULL_NODE_NOTICE) << "failed to download block " << block_id_ << " from " << download_from_ << ": "
85
                             << reason;
86
    }
87
    promise_.set_error(std::move(reason));
88
  }
89
  stop();
90
}
91

92
void DownloadBlockNew::alarm() {
93
  abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
94
}
95

96
void DownloadBlockNew::finish_query() {
97
  if (promise_) {
98
    promise_.set_value(std::move(block_));
99
  }
100
  stop();
101
}
102

103
void DownloadBlockNew::start_up() {
104
  alarm_timestamp() = timeout_;
105

106
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
107
    R.ensure();
108
    td::actor::send_closure(SelfId, &DownloadBlockNew::got_block_handle, R.move_as_ok());
109
  });
110

111
  td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
112
                          block_id_.is_valid() ? block_id_ : prev_id_, true, std::move(P));
113
}
114

115
void DownloadBlockNew::got_block_handle(BlockHandle handle) {
116
  handle_ = std::move(handle);
117

118
  if (!block_id_.is_valid()) {
119
    CHECK(prev_id_.is_valid());
120
    if (handle_->inited_next_left()) {
121
      block_id_ = handle_->one_next(true);
122
      block_.id = block_id_;
123
      handle_ = nullptr;
124
      start_up();
125
      return;
126
    }
127
  }
128

129
  if (block_id_.is_valid() &&
130
      (handle_->inited_proof() || (handle_->inited_proof_link() && allow_partial_proof_) || skip_proof_) &&
131
      handle_->received()) {
132
    CHECK(block_.id == block_id_);
133
    CHECK(handle_->id() == block_id_);
134
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
135
      if (R.is_error()) {
136
        td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query,
137
                                R.move_as_error_prefix("failed to get from db: "));
138
      } else {
139
        td::actor::send_closure(SelfId, &DownloadBlockNew::got_data_from_db, R.move_as_ok()->data());
140
      }
141
    });
142
    td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_data_from_db, handle_,
143
                            std::move(P));
144
    return;
145
  }
146

147
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<DownloadToken>> R) {
148
    if (R.is_error()) {
149
      td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query,
150
                              R.move_as_error_prefix("failed to get download token: "));
151
    } else {
152
      td::actor::send_closure(SelfId, &DownloadBlockNew::got_download_token, R.move_as_ok());
153
    }
154
  });
155
  td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_download_token, 1, priority_, timeout_,
156
                          std::move(P));
157
}
158

159
void DownloadBlockNew::got_download_token(std::unique_ptr<DownloadToken> token) {
160
  token_ = std::move(token);
161

162
  if (download_from_.is_zero() && client_.empty()) {
163
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::vector<adnl::AdnlNodeIdShort>> R) {
164
      if (R.is_error()) {
165
        td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query, R.move_as_error());
166
      } else {
167
        auto vec = R.move_as_ok();
168
        if (vec.size() == 0) {
169
          td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query,
170
                                  td::Status::Error(ErrorCode::notready, "no nodes"));
171
        } else {
172
          td::actor::send_closure(SelfId, &DownloadBlockNew::got_node_to_download, vec[0]);
173
        }
174
      }
175
    });
176

177
    td::actor::send_closure(overlays_, &overlay::Overlays::get_overlay_random_peers, local_id_, overlay_id_, 1,
178
                            std::move(P));
179
  } else {
180
    got_node_to_download(download_from_);
181
  }
182
}
183

184
void DownloadBlockNew::got_node_to_download(adnl::AdnlNodeIdShort node) {
185
  download_from_ = node;
186

187
  VLOG(FULL_NODE_DEBUG) << "downloading proof for " << block_id_;
188

189
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) mutable {
190
    if (R.is_error()) {
191
      td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query, R.move_as_error());
192
    } else {
193
      td::actor::send_closure(SelfId, &DownloadBlockNew::got_data, R.move_as_ok());
194
    }
195
  });
196

197
  td::BufferSlice q;
198
  if (block_id_.is_valid()) {
199
    q = create_serialize_tl_object<ton_api::tonNode_downloadBlockFull>(create_tl_block_id(block_id_));
200
  } else {
201
    q = create_serialize_tl_object<ton_api::tonNode_downloadNextBlockFull>(create_tl_block_id(prev_id_));
202
  }
203
  if (client_.empty()) {
204
    td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_,
205
                            "get_proof", std::move(P), td::Timestamp::in(15.0), std::move(q),
206
                            FullNode::max_proof_size() + FullNode::max_block_size() + 128, rldp_);
207
  } else {
208
    td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare",
209
                            create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(q)),
210
                            td::Timestamp::in(15.0), std::move(P));
211
  }
212
}
213

214
void DownloadBlockNew::got_data(td::BufferSlice data) {
215
  auto F = fetch_tl_object<ton_api::tonNode_DataFull>(std::move(data), true);
216

217
  if (F.is_error()) {
218
    abort_query(F.move_as_error_prefix("received invalid answer: "));
219
    return;
220
  }
221

222
  auto f = F.move_as_ok();
223
  if (f->get_id() == ton_api::tonNode_dataFullEmpty::ID) {
224
    abort_query(td::Status::Error(ErrorCode::notready, "node doesn't have this block"));
225
    return;
226
  }
227
  BlockIdExt id;
228
  td::BufferSlice proof, block_data;
229
  bool is_link;
230
  td::Status S = deserialize_block_full(*f, id, proof, block_data, is_link, overlay::Overlays::max_fec_broadcast_size());
231
  if (S.is_error()) {
232
    abort_query(S.move_as_error_prefix("cannot deserialize block: "));
233
    return;
234
  }
235

236
  if (!allow_partial_proof_ && is_link) {
237
    abort_query(td::Status::Error(ErrorCode::notready, "node doesn't have proof for this block"));
238
    return;
239
  }
240
  if (block_id_.is_valid() && id != block_id_) {
241
    abort_query(td::Status::Error(ErrorCode::notready, "received data for wrong block"));
242
    return;
243
  }
244
  block_.id = id;
245
  block_.data = std::move(block_data);
246
  if (td::sha256_bits256(block_.data.as_slice()) != id.file_hash) {
247
    abort_query(td::Status::Error(ErrorCode::notready, "received data with bad hash"));
248
    return;
249
  }
250

251
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
252
    if (R.is_error()) {
253
      td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query, R.move_as_error_prefix("received bad proof: "));
254
    } else {
255
      td::actor::send_closure(SelfId, &DownloadBlockNew::checked_block_proof);
256
    }
257
  });
258
  if (block_id_.is_valid()) {
259
    if (is_link) {
260
      td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_proof_link, block_id_,
261
                              std::move(proof), std::move(P));
262
    } else {
263
      td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_proof, block_id_,
264
                              std::move(proof), std::move(P));
265
    }
266
  } else {
267
    CHECK(!is_link);
268
    td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_is_next_proof, prev_id_, id,
269
                            std::move(proof), std::move(P));
270
  }
271
}
272

273
void DownloadBlockNew::got_data_from_db(td::BufferSlice data) {
274
  block_.data = std::move(data);
275
  finish_query();
276
}
277

278
void DownloadBlockNew::checked_block_proof() {
279
  finish_query();
280
}
281

282
}  // namespace fullnode
283

284
}  // namespace validator
285

286
}  // namespace ton
287

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.