Ton

Форк
0
/
validate-broadcast.cpp 
318 строк · 11.7 Кб
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 "validate-broadcast.hpp"
20
#include "fabric.h"
21
#include "adnl/utils.hpp"
22
#include "ton/ton-io.hpp"
23
#include "apply-block.hpp"
24

25
namespace ton {
26

27
namespace validator {
28

29
void ValidateBroadcast::abort_query(td::Status reason) {
30
  if (promise_) {
31
    VLOG(VALIDATOR_WARNING) << "aborting validate broadcast query for " << broadcast_.block_id << ": " << reason;
32
    promise_.set_error(std::move(reason));
33
  }
34
  stop();
35
}
36

37
void ValidateBroadcast::finish_query() {
38
  if (promise_) {
39
    VLOG(VALIDATOR_DEBUG) << "validated broadcast for " << broadcast_.block_id;
40
    promise_.set_result(td::Unit());
41
  }
42
  stop();
43
}
44

45
void ValidateBroadcast::alarm() {
46
  abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
47
}
48

49
void ValidateBroadcast::start_up() {
50
  VLOG(VALIDATOR_DEBUG) << "received broadcast for " << broadcast_.block_id;
51
  alarm_timestamp() = timeout_;
52

53
  auto hash = sha256_bits256(broadcast_.data.as_slice());
54
  if (hash != broadcast_.block_id.file_hash) {
55
    abort_query(td::Status::Error(ErrorCode::protoviolation, "filehash mismatch"));
56
    return;
57
  }
58

59
  if (broadcast_.block_id.is_masterchain()) {
60
    if (last_masterchain_block_handle_->id().id.seqno >= broadcast_.block_id.id.seqno) {
61
      finish_query();
62
      return;
63
    }
64
  }
65

66
  sig_set_ = create_signature_set(std::move(broadcast_.signatures));
67
  if (sig_set_.is_null()) {
68
    abort_query(td::Status::Error(ErrorCode::protoviolation, "bad signature set"));
69
    return;
70
  }
71

72
  if (broadcast_.block_id.is_masterchain()) {
73
    auto R = create_proof(broadcast_.block_id, broadcast_.proof.clone());
74
    if (R.is_error()) {
75
      abort_query(R.move_as_error_prefix("bad proof: "));
76
      return;
77
    }
78
    proof_ = R.move_as_ok();
79
    auto hR = proof_->get_basic_header_info();
80
    if (hR.is_error()) {
81
      abort_query(hR.move_as_error_prefix("bad proof: "));
82
      return;
83
    }
84
    header_info_ = hR.move_as_ok();
85
  } else {
86
    auto R = create_proof_link(broadcast_.block_id, broadcast_.proof.clone());
87
    if (R.is_error()) {
88
      abort_query(R.move_as_error_prefix("bad proof link: "));
89
      return;
90
    }
91
    proof_link_ = R.move_as_ok();
92
    auto hR = proof_link_->get_basic_header_info();
93
    if (hR.is_error()) {
94
      abort_query(hR.move_as_error_prefix("bad proof link: "));
95
      return;
96
    }
97
    header_info_ = hR.move_as_ok();
98
  }
99

100
  BlockSeqno key_block_seqno = header_info_.prev_key_mc_seqno;
101
  exact_key_block_handle_ = key_block_seqno <= last_known_masterchain_block_handle_->id().seqno();
102
  if (key_block_seqno < last_known_masterchain_block_handle_->id().seqno()) {
103
    if (key_block_seqno < last_masterchain_state_->get_seqno()) {
104
      BlockIdExt block_id;
105
      if (!last_masterchain_state_->get_old_mc_block_id(key_block_seqno, block_id)) {
106
        abort_query(td::Status::Error(ErrorCode::error, "too old reference key block"));
107
        return;
108
      }
109
      got_key_block_id(block_id);
110
    } else if (key_block_seqno == last_masterchain_state_->get_seqno()) {
111
      got_key_block_handle(last_masterchain_block_handle_);
112
    } else {
113
      auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ConstBlockHandle> R) {
114
        if (R.is_error()) {
115
          td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
116
                                  R.move_as_error_prefix("cannot find reference key block id: "));
117
        } else {
118
          td::actor::send_closure(SelfId, &ValidateBroadcast::got_key_block_handle, R.move_as_ok());
119
        }
120
      });
121
      td::actor::send_closure(manager_, &ValidatorManager::get_block_by_seqno_from_db,
122
                              AccountIdPrefixFull{masterchainId, 0}, key_block_seqno, std::move(P));
123
    }
124
  } else {
125
    got_key_block_handle(last_known_masterchain_block_handle_);
126
  }
127
}
128

129
void ValidateBroadcast::got_key_block_id(BlockIdExt block_id) {
130
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
131
    if (R.is_error()) {
132
      td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
133
                              R.move_as_error_prefix("cannot find reference key block handle: "));
134
    } else {
135
      td::actor::send_closure(SelfId, &ValidateBroadcast::got_key_block_handle, R.move_as_ok());
136
    }
137
  });
138
  td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, block_id, false, std::move(P));
139
}
140

141
void ValidateBroadcast::got_key_block_handle(ConstBlockHandle handle) {
142
  if (handle->id().seqno() == 0) {
143
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
144
      if (R.is_error()) {
145
        td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
146
                                R.move_as_error_prefix("failed to get zero state: "));
147
      } else {
148
        td::actor::send_closure(SelfId, &ValidateBroadcast::got_zero_state, td::Ref<MasterchainState>{R.move_as_ok()});
149
      }
150
    });
151
    td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, handle, std::move(P));
152
  } else {
153
    if (!handle->inited_proof() && !handle->inited_proof_link()) {
154
      abort_query(td::Status::Error(ErrorCode::notready, "reference key block proof not received"));
155
      return;
156
    }
157
    if (!handle->is_key_block()) {
158
      abort_query(td::Status::Error(ErrorCode::protoviolation, "reference key block is not key"));
159
      return;
160
    }
161

162
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ProofLink>> R) {
163
      if (R.is_error()) {
164
        td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
165
                                R.move_as_error_prefix("cannot get reference key block proof: "));
166
      } else {
167
        td::actor::send_closure(SelfId, &ValidateBroadcast::got_key_block_proof_link, R.move_as_ok());
168
      }
169
    });
170
    td::actor::send_closure(manager_, &ValidatorManager::get_block_proof_link_from_db, handle, std::move(P));
171
  }
172
}
173

174
void ValidateBroadcast::got_key_block_proof_link(td::Ref<ProofLink> key_proof_link) {
175
  key_proof_link_ = key_proof_link;
176
  auto confR = key_proof_link->get_key_block_config();
177
  if (confR.is_error()) {
178
    abort_query(confR.move_as_error_prefix("failed to extract config from key proof: "));
179
    return;
180
  }
181
  check_signatures_common(confR.move_as_ok());
182
}
183

184
void ValidateBroadcast::got_zero_state(td::Ref<MasterchainState> state) {
185
  zero_state_ = state;
186
  auto confR = state->get_config_holder();
187
  if (confR.is_error()) {
188
    abort_query(confR.move_as_error_prefix("failed to extract config from zero state: "));
189
    return;
190
  }
191
  check_signatures_common(confR.move_as_ok());
192
}
193

194
void ValidateBroadcast::check_signatures_common(td::Ref<ConfigHolder> conf) {
195
  auto val_set = conf->get_validator_set(broadcast_.block_id.shard_full(), header_info_.utime, header_info_.cc_seqno);
196
  if (val_set.is_null()) {
197
    abort_query(td::Status::Error(ErrorCode::notready, "failed to compute validator set"));
198
    return;
199
  }
200

201
  if (val_set->get_validator_set_hash() != header_info_.validator_set_hash) {
202
    if (!exact_key_block_handle_) {
203
      abort_query(td::Status::Error(ErrorCode::notready, "too new block, don't know recent enough key block"));
204
      return;
205
    } else {
206
      abort_query(td::Status::Error(ErrorCode::notready, "bad validator set hash"));
207
      return;
208
    }
209
  }
210
  auto S = val_set->check_signatures(broadcast_.block_id.root_hash, broadcast_.block_id.file_hash, sig_set_);
211
  if (S.is_ok()) {
212
    checked_signatures();
213
  } else {
214
    abort_query(S.move_as_error_prefix("failed signature check: "));
215
  }
216
}
217

218
void ValidateBroadcast::checked_signatures() {
219
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
220
    if (R.is_error()) {
221
      td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error_prefix("db error: "));
222
    } else {
223
      td::actor::send_closure(SelfId, &ValidateBroadcast::got_block_handle, R.move_as_ok());
224
    }
225
  });
226

227
  td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, broadcast_.block_id, true, std::move(P));
228
}
229

230
void ValidateBroadcast::got_block_handle(BlockHandle handle) {
231
  handle_ = std::move(handle);
232

233
  auto dataR = create_block(broadcast_.block_id, broadcast_.data.clone());
234
  if (dataR.is_error()) {
235
    abort_query(dataR.move_as_error_prefix("bad block data: "));
236
    return;
237
  }
238
  data_ = dataR.move_as_ok();
239

240
  if (handle_->received()) {
241
    written_block_data();
242
    return;
243
  }
244

245
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
246
    if (R.is_error()) {
247
      td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error());
248
    } else {
249
      td::actor::send_closure(SelfId, &ValidateBroadcast::written_block_data);
250
    }
251
  });
252

253
  td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, data_, std::move(P));
254
}
255

256
void ValidateBroadcast::written_block_data() {
257
  if (handle_->id().is_masterchain()) {
258
    if (handle_->inited_proof()) {
259
      checked_proof();
260
      return;
261
    }
262
    if (exact_key_block_handle_) {
263
      auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
264
        if (R.is_error()) {
265
          td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error_prefix("db error: "));
266
        } else {
267
          td::actor::send_closure(SelfId, &ValidateBroadcast::checked_proof);
268
        }
269
      });
270
      if (!key_proof_link_.is_null()) {
271
        run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P), key_proof_link_);
272
      } else {
273
        CHECK(zero_state_.not_null());
274
        run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P), zero_state_);
275
      }
276
    } else {
277
      checked_proof();
278
    }
279
  } else {
280
    if (handle_->inited_proof_link()) {
281
      checked_proof();
282
      return;
283
    }
284
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
285
      if (R.is_error()) {
286
        td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error_prefix("db error: "));
287
      } else {
288
        td::actor::send_closure(SelfId, &ValidateBroadcast::checked_proof);
289
      }
290
    });
291
    run_check_proof_link_query(broadcast_.block_id, proof_link_, manager_, timeout_, std::move(P));
292
  }
293
}
294

295
void ValidateBroadcast::checked_proof() {
296
  if (handle_->inited_proof() && handle_->is_key_block()) {
297
    td::actor::send_closure(manager_, &ValidatorManager::update_last_known_key_block, handle_, false);
298
  }
299
  if (handle_->inited_proof() && handle_->id().seqno() - last_masterchain_block_handle_->id().seqno() <= 16) {
300
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
301
      if (R.is_error()) {
302
        td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error());
303
      } else {
304
        td::actor::send_closure(SelfId, &ValidateBroadcast::finish_query);
305
      }
306
    });
307

308
    td::actor::create_actor<ApplyBlock>("applyblock", handle_->id(), data_, handle_->id(), manager_, timeout_,
309
                                        std::move(P))
310
        .release();
311
  } else {
312
    finish_query();
313
  }
314
}
315

316
}  // namespace validator
317

318
}  // namespace ton
319

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

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

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

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