mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
159
validator/CMakeLists.txt
Normal file
159
validator/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
#add_subdirectory(dummy0)
|
||||
add_subdirectory(impl)
|
||||
|
||||
set(VALIDATOR_DB_SOURCE
|
||||
db/archiver.cpp
|
||||
db/archiver.hpp
|
||||
db/blockdb.cpp
|
||||
db/blockdb.hpp
|
||||
db/celldb.cpp
|
||||
db/celldb.hpp
|
||||
db/files-async.hpp
|
||||
db/filedb.hpp
|
||||
db/filedb.cpp
|
||||
db/ltdb.hpp
|
||||
db/ltdb.cpp
|
||||
db/rootdb.cpp
|
||||
db/rootdb.hpp
|
||||
db/statedb.hpp
|
||||
db/statedb.cpp
|
||||
db/staticfilesdb.cpp
|
||||
db/staticfilesdb.hpp
|
||||
)
|
||||
|
||||
set(VALIDATOR_HEADERS
|
||||
block-handle.hpp
|
||||
get-next-key-blocks.h
|
||||
|
||||
downloaders/download-state.hpp
|
||||
downloaders/wait-block-data-disk.hpp
|
||||
downloaders/wait-block-data.hpp
|
||||
downloaders/wait-block-state-merge.hpp
|
||||
downloaders/wait-block-state.hpp
|
||||
|
||||
fabric.h
|
||||
interfaces/db.h
|
||||
interfaces/external-message.h
|
||||
interfaces/proof.h
|
||||
interfaces/shard.h
|
||||
interfaces/signature-set.h
|
||||
interfaces/validator-full-id.h
|
||||
interfaces/validator-manager.h
|
||||
interfaces/validator-set.h
|
||||
invariants.hpp
|
||||
|
||||
manager-disk.h
|
||||
manager-disk.hpp
|
||||
manager-init.h
|
||||
manager-init.hpp
|
||||
manager.h
|
||||
manager.hpp
|
||||
shard-client.hpp
|
||||
validate-broadcast.hpp
|
||||
validator-group.hpp
|
||||
validator-options.hpp
|
||||
validator.h
|
||||
)
|
||||
set(VALIDATOR_SOURCE
|
||||
apply-block.cpp
|
||||
block-handle.cpp
|
||||
get-next-key-blocks.cpp
|
||||
shard-client.cpp
|
||||
state-serializer.cpp
|
||||
token-manager.cpp
|
||||
validate-broadcast.cpp
|
||||
validator-full-id.cpp
|
||||
validator-group.cpp
|
||||
validator-options.cpp
|
||||
|
||||
downloaders/wait-block-data.cpp
|
||||
downloaders/wait-block-state.cpp
|
||||
downloaders/wait-block-state-merge.cpp
|
||||
downloaders/download-state.cpp
|
||||
|
||||
manager-init.cpp
|
||||
manager.cpp
|
||||
|
||||
${VALIDATOR_DB_SOURCE}
|
||||
|
||||
${VALIDATOR_HEADERS}
|
||||
)
|
||||
|
||||
set(DISK_VALIDATOR_SOURCE
|
||||
apply-block.cpp
|
||||
block-handle.cpp
|
||||
shard-client.cpp
|
||||
validator-full-id.cpp
|
||||
validator-group.cpp
|
||||
validator-options.cpp
|
||||
|
||||
downloaders/wait-block-data-disk.cpp
|
||||
downloaders/wait-block-state.cpp
|
||||
downloaders/wait-block-state-merge.cpp
|
||||
downloaders/download-state.cpp
|
||||
|
||||
manager-init.cpp
|
||||
manager-disk.cpp
|
||||
|
||||
${VALIDATOR_DB_SOURCE}
|
||||
)
|
||||
|
||||
set(FULL_NODE_SOURCE
|
||||
full-node.h
|
||||
full-node.hpp
|
||||
full-node.cpp
|
||||
full-node-shard.h
|
||||
full-node-shard.hpp
|
||||
full-node-shard.cpp
|
||||
|
||||
net/download-block.hpp
|
||||
net/download-block.cpp
|
||||
net/download-next-block.hpp
|
||||
net/download-next-block.cpp
|
||||
net/download-state.hpp
|
||||
net/download-state.cpp
|
||||
net/download-proof.hpp
|
||||
net/download-proof.cpp
|
||||
net/get-next-key-blocks.hpp
|
||||
net/get-next-key-blocks.cpp
|
||||
)
|
||||
|
||||
add_library(validator STATIC ${VALIDATOR_SOURCE})
|
||||
add_library(validator-disk STATIC ${DISK_VALIDATOR_SOURCE})
|
||||
add_library(full-node STATIC ${FULL_NODE_SOURCE})
|
||||
|
||||
target_include_directories(validator PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../crypto
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(validator-disk PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../crypto
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(full-node PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../crypto
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(validator PRIVATE tdutils tdactor adnl rldp tl_api dht tdfec
|
||||
overlay catchain validatorsession ton_crypto ton_block ton_db)
|
||||
|
||||
target_link_libraries(validator-disk PRIVATE tdutils tdactor adnl rldp tl_api dht tdfec
|
||||
overlay catchain validatorsession ton_crypto ton_block ton_db)
|
||||
|
||||
target_link_libraries(full-node PRIVATE tdutils tdactor adnl rldp tl_api dht tdfec
|
||||
overlay catchain validatorsession ton_crypto ton_block ton_db)
|
||||
254
validator/apply-block.cpp
Normal file
254
validator/apply-block.cpp
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "apply-block.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "validator/invariants.hpp"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "validator/fabric.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void ApplyBlock::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
VLOG(VALIDATOR_WARNING) << "aborting apply block query for " << id_ << ": " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ApplyBlock::finish_query() {
|
||||
VLOG(VALIDATOR_DEBUG) << "successfully finishing apply block query";
|
||||
handle_->set_processed();
|
||||
ValidatorInvariants::check_post_apply(handle_);
|
||||
|
||||
if (promise_) {
|
||||
promise_.set_value(td::Unit());
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ApplyBlock::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void ApplyBlock::start_up() {
|
||||
VLOG(VALIDATOR_DEBUG) << "running apply_block for " << id_;
|
||||
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::got_block_handle, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, id_, true, std::move(P));
|
||||
}
|
||||
|
||||
void ApplyBlock::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
|
||||
if (handle_->is_applied() && (!handle_->id().is_masterchain() || handle_->processed())) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_->is_applied()) {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), seqno = handle_->id().id.seqno](td::Result<BlockIdExt> R) {
|
||||
R.ensure();
|
||||
auto h = R.move_as_ok();
|
||||
if (h.id.seqno < seqno) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::finish_query);
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_top_masterchain_block, std::move(P));
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_->id().id.seqno == 0) {
|
||||
written_block_data();
|
||||
return;
|
||||
}
|
||||
if (handle_->id().is_masterchain() && !handle_->inited_proof()) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "proof is absent"));
|
||||
return;
|
||||
}
|
||||
if (!handle_->id().is_masterchain() && !handle_->inited_proof_link()) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "proof link is absent"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_->is_archived()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(handle_->inited_merge_before());
|
||||
CHECK(handle_->inited_split_after());
|
||||
CHECK(handle_->inited_prev());
|
||||
CHECK(handle_->inited_state_root_hash());
|
||||
CHECK(handle_->inited_logical_time());
|
||||
|
||||
if (handle_->received()) {
|
||||
written_block_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_.not_null()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, block_, std::move(P));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle = handle_](td::Result<td::Ref<BlockData>> R) {
|
||||
CHECK(handle->received());
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, apply_block_priority(), timeout_,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBlock::written_block_data() {
|
||||
if (handle_->is_applied() && handle_->processed()) {
|
||||
finish_query();
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::got_cur_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state, handle_, apply_block_priority(), timeout_,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBlock::got_cur_state(td::Ref<ShardState> state) {
|
||||
state_ = std::move(state);
|
||||
CHECK(handle_->received_state());
|
||||
written_state();
|
||||
}
|
||||
|
||||
void ApplyBlock::written_state() {
|
||||
if (handle_->is_applied() && handle_->processed()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_->id().id.seqno != 0 && !handle_->is_applied()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_next);
|
||||
}
|
||||
});
|
||||
|
||||
td::MultiPromise mp;
|
||||
auto g = mp.init_guard();
|
||||
g.add_promise(std::move(P));
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_next_block, handle_->one_prev(true), id_, g.get_promise());
|
||||
if (handle_->merge_before()) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_next_block, handle_->one_prev(false), id_,
|
||||
g.get_promise());
|
||||
}
|
||||
} else {
|
||||
written_next();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBlock::written_next() {
|
||||
if (handle_->is_applied() && handle_->processed()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_->id().id.seqno != 0) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::applied_prev);
|
||||
}
|
||||
});
|
||||
|
||||
td::MultiPromise mp;
|
||||
auto g = mp.init_guard();
|
||||
g.add_promise(std::move(P));
|
||||
run_apply_block_query(handle_->one_prev(true), td::Ref<BlockData>{}, manager_, timeout_, g.get_promise());
|
||||
if (handle_->merge_before()) {
|
||||
run_apply_block_query(handle_->one_prev(false), td::Ref<BlockData>{}, manager_, timeout_, g.get_promise());
|
||||
}
|
||||
} else {
|
||||
applied_prev();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBlock::applied_prev() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::applied_set);
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::new_block, handle_, state_, std::move(P));
|
||||
}
|
||||
|
||||
void ApplyBlock::applied_set() {
|
||||
handle_->set_applied();
|
||||
if (handle_->need_flush()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::finish_query);
|
||||
}
|
||||
});
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
} else {
|
||||
finish_query();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
80
validator/apply-block.hpp
Normal file
80
validator/apply-block.hpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
/*
|
||||
*
|
||||
* only for masterchain
|
||||
* --------------------
|
||||
* must ensure that block proof / proof_link is written
|
||||
* must ensure that prev, before_split, after_merge, state_root_hash and lt initialized
|
||||
* must initialize prev's next (to be sure, probably already initialized)
|
||||
* must write block data and state
|
||||
* must run new_block callback
|
||||
*
|
||||
*/
|
||||
|
||||
class ApplyBlock : public td::actor::Actor {
|
||||
public:
|
||||
ApplyBlock(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Unit> promise)
|
||||
: id_(id), block_(std::move(block)), manager_(manager), timeout_(timeout), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
static constexpr td::uint32 apply_block_priority() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void written_block_data();
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void got_cur_state(td::Ref<ShardState> state);
|
||||
void written_state();
|
||||
void written_next();
|
||||
void applied_prev();
|
||||
void applied_set();
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
td::Ref<BlockData> block_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
BlockHandle handle_;
|
||||
td::Ref<ShardState> state_;
|
||||
|
||||
td::PerfWarningTimer perf_timer_{"applyblock", 0.1};
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
60
validator/block-handle.cpp
Normal file
60
validator/block-handle.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "block-handle.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void BlockHandleImpl::flush(td::actor::ActorId<ValidatorManagerInterface> manager, BlockHandle self,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(manager, &ValidatorManager::write_handle, self, std::move(promise));
|
||||
}
|
||||
|
||||
td::BufferSlice BlockHandleImpl::serialize() const {
|
||||
while (locked()) {
|
||||
}
|
||||
auto flags = flags_.load(std::memory_order_consume) & ~Flags::dbf_processed;
|
||||
return create_serialize_tl_object<ton_api::db_block_info>(
|
||||
create_tl_block_id(id_), flags, (flags & dbf_inited_prev_left) ? create_tl_block_id(prev_[0]) : nullptr,
|
||||
(flags & dbf_inited_prev_right) ? create_tl_block_id(prev_[1]) : nullptr,
|
||||
(flags & dbf_inited_next_left) ? create_tl_block_id(next_[0]) : nullptr,
|
||||
(flags & dbf_inited_next_right) ? create_tl_block_id(next_[1]) : nullptr, (flags & dbf_inited_lt) ? lt_ : 0,
|
||||
(flags & dbf_inited_ts) ? ts_ : 0, (flags & dbf_inited_state) ? state_ : RootHash::zero());
|
||||
}
|
||||
|
||||
BlockHandleImpl::BlockHandleImpl(td::BufferSlice data) {
|
||||
auto obj = fetch_tl_object<ton_api::db_block_info>(std::move(data), true).move_as_ok();
|
||||
flags_ = obj->flags_ & ~Flags::dbf_processed;
|
||||
id_ = create_block_id(obj->id_);
|
||||
prev_[0] = (flags_ & dbf_inited_prev_left) ? create_block_id(obj->prev_left_) : BlockIdExt{};
|
||||
prev_[1] = (flags_ & dbf_inited_prev_right) ? create_block_id(obj->prev_right_) : BlockIdExt{};
|
||||
next_[0] = (flags_ & dbf_inited_next_left) ? create_block_id(obj->next_left_) : BlockIdExt{};
|
||||
next_[1] = (flags_ & dbf_inited_next_right) ? create_block_id(obj->next_right_) : BlockIdExt{};
|
||||
lt_ = (flags_ & dbf_inited_lt) ? obj->lt_ : 0;
|
||||
ts_ = (flags_ & dbf_inited_ts) ? obj->ts_ : 0;
|
||||
state_ = (flags_ & dbf_inited_state) ? obj->state_ : RootHash::zero();
|
||||
get_thread_safe_counter().add(1);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
503
validator/block-handle.hpp
Normal file
503
validator/block-handle.hpp
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/block-handle.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "td/actor/actor.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
#include "td/utils/ThreadSafeCounter.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorManager;
|
||||
|
||||
struct BlockHandleImpl : public BlockHandleInterface {
|
||||
private:
|
||||
enum Flags : td::uint32 {
|
||||
dbf_masterchain = 0x1,
|
||||
dbf_inited_prev_left = 0x2,
|
||||
dbf_inited_prev_right = 0x4,
|
||||
dbf_inited_next_left = 0x8,
|
||||
dbf_inited_next_right = 0x10,
|
||||
dbf_inited_split_after = 0x20,
|
||||
dbf_split_after = 0x40,
|
||||
dbf_inited_merge_before = 0x80,
|
||||
dbf_merge_before = 0x100,
|
||||
dbf_received = 0x200,
|
||||
dbf_is_key_block = 0x400,
|
||||
dbf_inited_proof = 0x800,
|
||||
dbf_inited_proof_link = 0x1000,
|
||||
dbf_inited_lt = 0x2000,
|
||||
dbf_inited_ts = 0x4000,
|
||||
dbf_inited_is_key_block = 0x8000,
|
||||
dbf_inited_state = 0x20000,
|
||||
dbf_inited_signatures = 0x40000,
|
||||
dbf_inited_state_boc = 0x100000,
|
||||
dbf_archived = 0x200000,
|
||||
dbf_applied = 0x400000,
|
||||
dbf_moved = 0x1000000,
|
||||
dbf_deleted = 0x2000000,
|
||||
dbf_deleted_boc = 0x4000000,
|
||||
dbf_processed = 0x10000000,
|
||||
};
|
||||
|
||||
std::atomic<td::uint64> version_{0};
|
||||
std::atomic<td::uint32> written_version_{0};
|
||||
BlockIdExt id_;
|
||||
std::atomic<td::uint32> flags_{0};
|
||||
std::array<BlockIdExt, 2> prev_;
|
||||
std::array<BlockIdExt, 2> next_;
|
||||
LogicalTime lt_;
|
||||
UnixTime ts_;
|
||||
RootHash state_;
|
||||
|
||||
static constexpr td::uint64 lock_const() {
|
||||
return static_cast<td::uint64>(1) << 32;
|
||||
}
|
||||
bool locked() const {
|
||||
return version_.load(std::memory_order_consume) >> 32;
|
||||
}
|
||||
void lock() {
|
||||
version_ += 1 + lock_const();
|
||||
}
|
||||
void unlock() {
|
||||
version_ -= lock_const();
|
||||
}
|
||||
|
||||
public:
|
||||
BlockIdExt id() const override {
|
||||
return id_;
|
||||
}
|
||||
bool received() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_received;
|
||||
}
|
||||
bool moved_to_storage() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_moved;
|
||||
}
|
||||
bool deleted() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_deleted;
|
||||
}
|
||||
bool inited_next_left() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_next_left;
|
||||
}
|
||||
bool inited_next_right() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_next_right;
|
||||
}
|
||||
bool inited_next() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (!(f & Flags::dbf_inited_next_left)) {
|
||||
return false;
|
||||
}
|
||||
if (f & Flags::dbf_inited_next_right) {
|
||||
return true;
|
||||
}
|
||||
if ((f & Flags::dbf_inited_split_after) && !(f & Flags::dbf_split_after)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool inited_prev_left() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_prev_left;
|
||||
}
|
||||
bool inited_prev_right() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_prev_right;
|
||||
}
|
||||
bool inited_prev() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (!(f & Flags::dbf_inited_prev_left)) {
|
||||
return false;
|
||||
}
|
||||
if (f & Flags::dbf_inited_prev_right) {
|
||||
return true;
|
||||
}
|
||||
if ((f & Flags::dbf_inited_merge_before) && !(f & Flags::dbf_merge_before)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool inited_proof() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_proof;
|
||||
}
|
||||
bool inited_proof_link() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_proof_link;
|
||||
}
|
||||
bool inited_signatures() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_signatures;
|
||||
}
|
||||
bool inited_split_after() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_split_after;
|
||||
}
|
||||
bool inited_merge_before() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_merge_before;
|
||||
}
|
||||
bool inited_is_key_block() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
return f & Flags::dbf_inited_is_key_block;
|
||||
}
|
||||
bool split_after() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
CHECK(f & Flags::dbf_inited_split_after);
|
||||
return f & Flags::dbf_split_after;
|
||||
}
|
||||
bool merge_before() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
CHECK(f & Flags::dbf_inited_merge_before);
|
||||
return f & Flags::dbf_merge_before;
|
||||
}
|
||||
bool is_key_block() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
CHECK(f & Flags::dbf_inited_is_key_block);
|
||||
return f & Flags::dbf_is_key_block;
|
||||
}
|
||||
|
||||
bool inited_state_root_hash() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_state;
|
||||
}
|
||||
bool inited_state_boc() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_state_boc;
|
||||
}
|
||||
bool deleted_state_boc() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_deleted_boc;
|
||||
}
|
||||
bool received_state() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_state_boc;
|
||||
}
|
||||
bool need_flush() const override {
|
||||
return written_version_.load(std::memory_order_consume) < version();
|
||||
}
|
||||
bool is_zero() const override {
|
||||
return id_.id.seqno == 0;
|
||||
}
|
||||
bool is_archived() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_archived;
|
||||
}
|
||||
bool is_applied() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_applied;
|
||||
}
|
||||
std::vector<BlockIdExt> prev() const override {
|
||||
if (is_zero()) {
|
||||
return {};
|
||||
}
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
CHECK(f & Flags::dbf_inited_merge_before);
|
||||
if (!(f & Flags::dbf_merge_before)) {
|
||||
CHECK(f & Flags::dbf_inited_prev_left);
|
||||
return {prev_[0]};
|
||||
} else {
|
||||
CHECK(f & Flags::dbf_inited_prev_left);
|
||||
CHECK(f & Flags::dbf_inited_prev_right);
|
||||
return {prev_[0], prev_[1]};
|
||||
}
|
||||
}
|
||||
BlockIdExt one_prev(bool left) const override {
|
||||
CHECK(!is_zero());
|
||||
if (left) {
|
||||
CHECK(flags_.load(std::memory_order_consume) & Flags::dbf_inited_prev_left);
|
||||
} else {
|
||||
CHECK(flags_.load(std::memory_order_consume) & Flags::dbf_inited_prev_right);
|
||||
}
|
||||
return prev_[left ? 0 : 1];
|
||||
}
|
||||
std::vector<BlockIdExt> next() const override {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
CHECK(f & Flags::dbf_inited_split_after);
|
||||
if (!(f & Flags::dbf_split_after)) {
|
||||
CHECK(f & Flags::dbf_inited_next_left);
|
||||
return {next_[0]};
|
||||
} else {
|
||||
CHECK(f & Flags::dbf_inited_next_left);
|
||||
CHECK(f & Flags::dbf_inited_next_right);
|
||||
return {next_[0], next_[1]};
|
||||
}
|
||||
}
|
||||
BlockIdExt one_next(bool left) const override {
|
||||
if (left) {
|
||||
CHECK(flags_.load(std::memory_order_consume) & Flags::dbf_inited_next_left);
|
||||
} else {
|
||||
CHECK(flags_.load(std::memory_order_consume) & Flags::dbf_inited_next_right);
|
||||
}
|
||||
return next_[left ? 0 : 1];
|
||||
}
|
||||
RootHash state() const override {
|
||||
CHECK(flags_.load(std::memory_order_consume) & Flags::dbf_inited_state);
|
||||
return state_;
|
||||
}
|
||||
|
||||
bool processed() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_processed;
|
||||
}
|
||||
void set_processed() override {
|
||||
// does not increase version
|
||||
flags_ |= Flags::dbf_processed;
|
||||
}
|
||||
|
||||
td::uint32 version() const override {
|
||||
return static_cast<td::uint32>(version_.load(std::memory_order_consume));
|
||||
}
|
||||
void flush(td::actor::ActorId<ValidatorManagerInterface> manager, BlockHandle self,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
void flushed_upto(td::uint32 version) override {
|
||||
if (version > written_version_.load(std::memory_order_consume)) {
|
||||
written_version_.store(version, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
bool inited_logical_time() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_lt;
|
||||
}
|
||||
LogicalTime logical_time() const override {
|
||||
CHECK(inited_logical_time());
|
||||
return lt_;
|
||||
}
|
||||
void set_logical_time(LogicalTime lt) override {
|
||||
if (inited_logical_time()) {
|
||||
CHECK(lt_ == lt);
|
||||
} else {
|
||||
lock();
|
||||
lt_ = lt;
|
||||
flags_ |= Flags::dbf_inited_lt;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
bool inited_unix_time() const override {
|
||||
return flags_.load(std::memory_order_consume) & Flags::dbf_inited_ts;
|
||||
}
|
||||
UnixTime unix_time() const override {
|
||||
CHECK(inited_unix_time());
|
||||
return ts_;
|
||||
}
|
||||
void set_unix_time(UnixTime ts) override {
|
||||
if (inited_unix_time()) {
|
||||
CHECK(ts_ == ts);
|
||||
} else {
|
||||
lock();
|
||||
ts_ = ts;
|
||||
flags_ |= Flags::dbf_inited_ts;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_proof() override {
|
||||
if (!inited_proof()) {
|
||||
lock();
|
||||
flags_ |= Flags::dbf_inited_proof;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_proof_link() override {
|
||||
if (!inited_proof_link()) {
|
||||
lock();
|
||||
flags_ |= Flags::dbf_inited_proof_link;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_signatures() override {
|
||||
if (!inited_signatures()) {
|
||||
lock();
|
||||
flags_ |= Flags::dbf_inited_signatures;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_next_left(BlockIdExt next) {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_next_left) {
|
||||
LOG_CHECK(next_[0] == next) << "id=" << id_ << " next=" << next_[0] << " to_be_next=" << next;
|
||||
} else {
|
||||
lock();
|
||||
next_[0] = next;
|
||||
flags_ |= Flags::dbf_inited_next_left;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_next_right(BlockIdExt next) {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_next_right) {
|
||||
LOG_CHECK(next_[1] == next) << "id=" << id_ << " next=" << next_[1] << " to_be_next=" << next;
|
||||
} else {
|
||||
lock();
|
||||
next_[1] = next;
|
||||
flags_ |= Flags::dbf_inited_next_right;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_next(BlockIdExt next) override {
|
||||
bool right = shard_child(id_.id.shard, false) == next.id.shard;
|
||||
if (right) {
|
||||
set_next_right(next);
|
||||
} else {
|
||||
set_next_left(next);
|
||||
}
|
||||
}
|
||||
void set_prev_left(BlockIdExt prev) {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_prev_left) {
|
||||
LOG_CHECK(prev_[0] == prev) << "id=" << id_ << " prev=" << prev_[0] << " to_be_prev=" << prev;
|
||||
} else {
|
||||
lock();
|
||||
prev_[0] = prev;
|
||||
flags_ |= Flags::dbf_inited_prev_left;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_prev_right(BlockIdExt prev) {
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_prev_right) {
|
||||
LOG_CHECK(prev_[1] == prev) << "id=" << id_ << " prev=" << prev_[1] << " to_be_prev=" << prev;
|
||||
} else {
|
||||
lock();
|
||||
prev_[1] = prev;
|
||||
flags_ |= Flags::dbf_inited_prev_right;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_prev(BlockIdExt prev) override {
|
||||
bool right = shard_child(id_.id.shard, false) == prev.id.shard;
|
||||
if (right) {
|
||||
set_prev_right(prev);
|
||||
} else {
|
||||
set_prev_left(prev);
|
||||
}
|
||||
}
|
||||
void set_received() override {
|
||||
if (flags_.load(std::memory_order_consume) & Flags::dbf_received) {
|
||||
return;
|
||||
}
|
||||
lock();
|
||||
flags_ |= Flags::dbf_received;
|
||||
unlock();
|
||||
}
|
||||
void set_moved_to_storage() override {
|
||||
if (flags_.load(std::memory_order_consume) & Flags::dbf_moved) {
|
||||
return;
|
||||
}
|
||||
lock();
|
||||
flags_ |= Flags::dbf_moved;
|
||||
unlock();
|
||||
}
|
||||
void set_deleted() override {
|
||||
if (flags_.load(std::memory_order_consume) & Flags::dbf_deleted) {
|
||||
return;
|
||||
}
|
||||
lock();
|
||||
flags_ |= Flags::dbf_deleted;
|
||||
unlock();
|
||||
}
|
||||
void set_split(bool value) override {
|
||||
td::uint32 v = value ? static_cast<td::uint32>(Flags::dbf_split_after) : 0;
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_split_after) {
|
||||
CHECK((f & Flags::dbf_split_after) == v);
|
||||
} else {
|
||||
lock();
|
||||
flags_ |= v | Flags::dbf_inited_split_after;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_merge(bool value) override {
|
||||
td::uint32 v = value ? static_cast<td::uint32>(Flags::dbf_merge_before) : 0;
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_merge_before) {
|
||||
CHECK((f & Flags::dbf_merge_before) == v);
|
||||
} else {
|
||||
lock();
|
||||
flags_ |= v | Flags::dbf_inited_merge_before;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_is_key_block(bool value) override {
|
||||
td::uint32 v = value ? static_cast<td::uint32>(Flags::dbf_is_key_block) : 0;
|
||||
auto f = flags_.load(std::memory_order_consume);
|
||||
if (f & Flags::dbf_inited_is_key_block) {
|
||||
CHECK((f & Flags::dbf_is_key_block) == v);
|
||||
} else {
|
||||
lock();
|
||||
flags_ |= v | Flags::dbf_inited_is_key_block;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_state_root_hash(RootHash hash) override {
|
||||
if (!(flags_.load(std::memory_order_consume) & Flags::dbf_inited_state)) {
|
||||
lock();
|
||||
state_ = hash;
|
||||
flags_ |= Flags::dbf_inited_state;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_state_boc() override {
|
||||
if (!inited_state_boc()) {
|
||||
CHECK(inited_state_root_hash());
|
||||
lock();
|
||||
flags_ |= Flags::dbf_inited_state_boc;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_deleted_state_boc() override {
|
||||
if (flags_.load(std::memory_order_consume) & Flags::dbf_deleted_boc) {
|
||||
return;
|
||||
}
|
||||
lock();
|
||||
flags_ |= Flags::dbf_deleted_boc;
|
||||
unlock();
|
||||
}
|
||||
void set_archived() override {
|
||||
if (!is_archived()) {
|
||||
lock();
|
||||
flags_ |= Flags::dbf_archived;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
void set_applied() override {
|
||||
if (!is_applied()) {
|
||||
lock();
|
||||
flags_ |= Flags::dbf_applied;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
td::BufferSlice serialize() const override;
|
||||
BlockHandleImpl(BlockIdExt id)
|
||||
: id_(id), flags_(id_.is_masterchain() ? static_cast<td::uint32>(dbf_masterchain) : 0) {
|
||||
get_thread_safe_counter().add(1);
|
||||
}
|
||||
BlockHandleImpl(td::BufferSlice data);
|
||||
~BlockHandleImpl() {
|
||||
CHECK(!need_flush());
|
||||
get_thread_safe_counter().add(-1);
|
||||
}
|
||||
|
||||
static td::NamedThreadSafeCounter::CounterRef get_thread_safe_counter() {
|
||||
static auto res = td::NamedThreadSafeCounter::get_default().get_counter("BlockHandleImpl");
|
||||
return res;
|
||||
}
|
||||
|
||||
static BlockHandle create_empty(BlockIdExt id) {
|
||||
return std::make_shared<BlockHandleImpl>(id);
|
||||
}
|
||||
|
||||
static BlockHandle create(td::BufferSlice data) {
|
||||
return std::make_shared<BlockHandleImpl>(std::move(data));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
147
validator/db/archiver.cpp
Normal file
147
validator/db/archiver.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "archiver.hpp"
|
||||
#include "rootdb.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
BlockArchiver::BlockArchiver(BlockIdExt block_id, td::actor::ActorId<RootDb> root_db,
|
||||
td::actor::ActorId<FileDb> file_db, td::actor::ActorId<FileDb> archive_db,
|
||||
td::Promise<td::Unit> promise)
|
||||
: block_id_(block_id), root_db_(root_db), file_db_(file_db), archive_db_(archive_db), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void BlockArchiver::start_up() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::got_block_handle, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(root_db_, &RootDb::get_block_handle_external, block_id_, false, std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
if (handle_->moved_to_storage()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!handle_->is_applied() && !handle_->is_archived()) {
|
||||
// no need for this block
|
||||
// probably this block not in final chain
|
||||
// this will eventually delete all associated data
|
||||
written_block_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!handle_->inited_proof()) {
|
||||
written_proof();
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::got_proof, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Proof{block_id_}}, std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::got_proof(td::BufferSlice data) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::written_proof);
|
||||
});
|
||||
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::Proof{block_id_}}, std::move(data),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::written_proof() {
|
||||
if (!handle_->inited_proof_link()) {
|
||||
written_proof_link();
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::got_proof_link, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::ProofLink{block_id_}}, std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::got_proof_link(td::BufferSlice data) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::written_proof_link);
|
||||
});
|
||||
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::ProofLink{block_id_}},
|
||||
std::move(data), std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::written_proof_link() {
|
||||
if (!handle_->received()) {
|
||||
written_block_data();
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::got_block_data, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Block{block_id_}}, std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::got_block_data(td::BufferSlice data) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::written_block_data);
|
||||
});
|
||||
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::Block{block_id_}}, std::move(data),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::written_block_data() {
|
||||
handle_->set_moved_to_storage();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::finish_query);
|
||||
});
|
||||
td::actor::send_closure(root_db_, &RootDb::store_block_handle, handle_, std::move(P));
|
||||
}
|
||||
|
||||
void BlockArchiver::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(td::Unit());
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void BlockArchiver::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
VLOG(VALIDATOR_WARNING) << "failed to archive block " << block_id_ << ": " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
62
validator/db/archiver.hpp
Normal file
62
validator/db/archiver.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "td/actor/actor.h"
|
||||
#include "validator/interfaces/block-handle.h"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb;
|
||||
class FileDb;
|
||||
|
||||
class BlockArchiver : public td::actor::Actor {
|
||||
public:
|
||||
BlockArchiver(BlockIdExt block_id, td::actor::ActorId<RootDb> root_db, td::actor::ActorId<FileDb> file_db,
|
||||
td::actor::ActorId<FileDb> archive_db, td::Promise<td::Unit> promise);
|
||||
|
||||
void abort_query(td::Status error);
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void got_proof(td::BufferSlice data);
|
||||
void written_proof();
|
||||
void got_proof_link(td::BufferSlice data);
|
||||
void written_proof_link();
|
||||
void got_block_data(td::BufferSlice data);
|
||||
void written_block_data();
|
||||
void finish_query();
|
||||
|
||||
private:
|
||||
BlockIdExt block_id_;
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
td::actor::ActorId<FileDb> file_db_;
|
||||
td::actor::ActorId<FileDb> archive_db_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
BlockHandle handle_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
234
validator/db/blockdb.cpp
Normal file
234
validator/db/blockdb.cpp
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "blockdb.hpp"
|
||||
#include "rootdb.hpp"
|
||||
#include "validator/fabric.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "files-async.hpp"
|
||||
#include "td/db/RocksDb.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void BlockDb::store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
if (!handle->id().is_valid()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "invalid block id"));
|
||||
return;
|
||||
}
|
||||
auto lru_key = get_block_lru_key(handle->id());
|
||||
auto value_key = get_block_value_key(handle->id());
|
||||
while (handle->need_flush()) {
|
||||
auto version = handle->version();
|
||||
auto R = get_block_value(value_key);
|
||||
if (R.is_ok()) {
|
||||
kv_->begin_transaction().ensure();
|
||||
set_block_value(value_key, handle->serialize());
|
||||
kv_->commit_transaction().ensure();
|
||||
} else {
|
||||
CHECK(get_block_lru(lru_key).is_error());
|
||||
auto empty = get_block_lru_empty_key_hash();
|
||||
auto ER = get_block_lru(empty);
|
||||
ER.ensure();
|
||||
auto E = ER.move_as_ok();
|
||||
|
||||
auto PR = get_block_lru(E.prev);
|
||||
PR.ensure();
|
||||
auto P = PR.move_as_ok();
|
||||
CHECK(P.next == empty);
|
||||
|
||||
DbEntry D{handle->id(), E.prev, empty};
|
||||
|
||||
E.prev = lru_key;
|
||||
P.next = lru_key;
|
||||
|
||||
if (P.is_empty()) {
|
||||
E.next = lru_key;
|
||||
P.prev = lru_key;
|
||||
}
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
set_block_value(value_key, handle->serialize());
|
||||
set_block_lru(empty, std::move(E));
|
||||
set_block_lru(D.prev, std::move(P));
|
||||
set_block_lru(lru_key, std::move(D));
|
||||
kv_->commit_transaction().ensure();
|
||||
}
|
||||
handle->flushed_upto(version);
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void BlockDb::get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) {
|
||||
if (!id.is_valid()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "invalid block id"));
|
||||
return;
|
||||
}
|
||||
CHECK(id.is_valid());
|
||||
auto key_hash = get_block_value_key(id);
|
||||
auto B = get_block_value(key_hash);
|
||||
if (B.is_error()) {
|
||||
promise.set_error(B.move_as_error());
|
||||
return;
|
||||
}
|
||||
promise.set_result(create_block_handle(B.move_as_ok()));
|
||||
}
|
||||
|
||||
void BlockDb::start_up() {
|
||||
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
|
||||
alarm_timestamp() = td::Timestamp::in(0.1);
|
||||
|
||||
auto empty = get_block_lru_empty_key_hash();
|
||||
if (get_block_lru(empty).is_error()) {
|
||||
DbEntry e{BlockIdExt{}, empty, empty};
|
||||
kv_->begin_transaction().ensure();
|
||||
set_block_lru(empty, std::move(e));
|
||||
kv_->commit_transaction().ensure();
|
||||
}
|
||||
last_gc_ = empty;
|
||||
}
|
||||
|
||||
BlockDb::BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
|
||||
}
|
||||
|
||||
BlockDb::KeyHash BlockDb::get_block_lru_key(BlockIdExt id) {
|
||||
if (!id.is_valid()) {
|
||||
return KeyHash::zero();
|
||||
} else {
|
||||
auto obj = create_tl_object<ton_api::db_blockdb_key_lru>(create_tl_block_id(id));
|
||||
return get_tl_object_sha_bits256(obj);
|
||||
}
|
||||
}
|
||||
|
||||
BlockDb::KeyHash BlockDb::get_block_value_key(BlockIdExt id) {
|
||||
CHECK(id.is_valid());
|
||||
auto obj = create_tl_object<ton_api::db_blockdb_key_value>(create_tl_block_id(id));
|
||||
return get_tl_object_sha_bits256(obj);
|
||||
}
|
||||
|
||||
td::Result<BlockDb::DbEntry> BlockDb::get_block_lru(KeyHash key_hash) {
|
||||
std::string value;
|
||||
auto R = kv_->get(key_hash.as_slice(), value);
|
||||
R.ensure();
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
return td::Status::Error(ErrorCode::notready, "not in db");
|
||||
}
|
||||
auto v = fetch_tl_object<ton_api::db_blockdb_lru>(td::BufferSlice{value}, true);
|
||||
v.ensure();
|
||||
return DbEntry{v.move_as_ok()};
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> BlockDb::get_block_value(KeyHash key_hash) {
|
||||
std::string value;
|
||||
auto R = kv_->get(key_hash.as_slice(), value);
|
||||
R.ensure();
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
return td::Status::Error(ErrorCode::notready, "not in db");
|
||||
}
|
||||
return td::BufferSlice{value};
|
||||
}
|
||||
|
||||
void BlockDb::set_block_lru(KeyHash key_hash, DbEntry e) {
|
||||
kv_->set(key_hash.as_slice(), serialize_tl_object(e.release(), true)).ensure();
|
||||
}
|
||||
|
||||
void BlockDb::set_block_value(KeyHash key_hash, td::BufferSlice value) {
|
||||
kv_->set(key_hash.as_slice(), std::move(value)).ensure();
|
||||
}
|
||||
|
||||
void BlockDb::alarm() {
|
||||
auto R = get_block_lru(last_gc_);
|
||||
R.ensure();
|
||||
|
||||
auto N = R.move_as_ok();
|
||||
if (N.is_empty()) {
|
||||
last_gc_ = N.next;
|
||||
alarm_timestamp() = td::Timestamp::in(0.01);
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &BlockDb::skip_gc);
|
||||
} else {
|
||||
auto value = R.move_as_ok();
|
||||
if (!value) {
|
||||
td::actor::send_closure(SelfId, &BlockDb::skip_gc);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &BlockDb::gc);
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(root_db_, &RootDb::allow_block_gc, N.block_id, std::move(P));
|
||||
}
|
||||
|
||||
void BlockDb::gc() {
|
||||
auto FR = get_block_lru(last_gc_);
|
||||
FR.ensure();
|
||||
auto F = FR.move_as_ok();
|
||||
|
||||
auto PR = get_block_lru(F.prev);
|
||||
PR.ensure();
|
||||
auto P = PR.move_as_ok();
|
||||
auto NR = get_block_lru(F.next);
|
||||
NR.ensure();
|
||||
auto N = NR.move_as_ok();
|
||||
|
||||
P.next = F.next;
|
||||
N.prev = F.prev;
|
||||
if (P.is_empty() && N.is_empty()) {
|
||||
P.prev = P.next;
|
||||
N.next = N.prev;
|
||||
}
|
||||
|
||||
auto value_key = get_block_value_key(F.block_id);
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->erase(last_gc_.as_slice()).ensure();
|
||||
kv_->erase(value_key.as_slice()).ensure();
|
||||
set_block_lru(F.prev, std::move(P));
|
||||
set_block_lru(F.next, std::move(N));
|
||||
kv_->commit_transaction().ensure();
|
||||
alarm_timestamp() = td::Timestamp::now();
|
||||
|
||||
DCHECK(get_block_lru(last_gc_).is_error());
|
||||
last_gc_ = F.next;
|
||||
}
|
||||
|
||||
void BlockDb::skip_gc() {
|
||||
auto R = get_block_lru(last_gc_);
|
||||
R.ensure();
|
||||
|
||||
auto N = R.move_as_ok();
|
||||
last_gc_ = N.next;
|
||||
alarm_timestamp() = td::Timestamp::in(0.01);
|
||||
}
|
||||
|
||||
BlockDb::DbEntry::DbEntry(tl_object_ptr<ton_api::db_blockdb_lru> entry)
|
||||
: block_id(create_block_id(entry->id_)), prev(entry->prev_), next(entry->next_) {
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::db_blockdb_lru> BlockDb::DbEntry::release() {
|
||||
return create_tl_object<ton_api::db_blockdb_lru>(create_tl_block_id(block_id), prev, next);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
86
validator/db/blockdb.hpp
Normal file
86
validator/db/blockdb.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "validator/interfaces/block-handle.h"
|
||||
#include "validator/interfaces/db.h"
|
||||
#include "td/db/KeyValueAsync.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb;
|
||||
|
||||
class BlockDb : public td::actor::Actor {
|
||||
public:
|
||||
void store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise);
|
||||
void get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise);
|
||||
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
|
||||
void gc();
|
||||
void skip_gc();
|
||||
|
||||
BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path);
|
||||
|
||||
private:
|
||||
using KeyHash = td::Bits256;
|
||||
struct DbEntry {
|
||||
BlockIdExt block_id;
|
||||
KeyHash prev;
|
||||
KeyHash next;
|
||||
|
||||
DbEntry(tl_object_ptr<ton_api::db_blockdb_lru> entry);
|
||||
DbEntry() {
|
||||
}
|
||||
DbEntry(BlockIdExt block_id, KeyHash prev, KeyHash next) : block_id(block_id), prev(prev), next(next) {
|
||||
}
|
||||
tl_object_ptr<ton_api::db_blockdb_lru> release();
|
||||
bool is_empty() const {
|
||||
return !block_id.is_valid();
|
||||
}
|
||||
};
|
||||
static KeyHash get_block_lru_key(BlockIdExt block_id);
|
||||
static KeyHash get_block_value_key(BlockIdExt block_id);
|
||||
static KeyHash get_block_lru_empty_key_hash() {
|
||||
return KeyHash::zero();
|
||||
}
|
||||
|
||||
td::Result<DbEntry> get_block_lru(KeyHash key);
|
||||
td::Result<td::BufferSlice> get_block_value(KeyHash key);
|
||||
|
||||
void set_block_lru(KeyHash key_hash, DbEntry e);
|
||||
void set_block_value(KeyHash key_hash, td::BufferSlice data);
|
||||
|
||||
std::shared_ptr<td::KeyValue> kv_;
|
||||
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
|
||||
std::string db_path_;
|
||||
|
||||
KeyHash last_gc_ = KeyHash::zero();
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
283
validator/db/celldb.cpp
Normal file
283
validator/db/celldb.cpp
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "celldb.hpp"
|
||||
#include "rootdb.hpp"
|
||||
|
||||
#include "td/db/RocksDb.h"
|
||||
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
CellDbIn::CellDbIn(td::actor::ActorId<RootDb> root_db, td::actor::ActorId<CellDb> parent, std::string path)
|
||||
: root_db_(root_db), parent_(parent), path_(std::move(path)) {
|
||||
}
|
||||
|
||||
void CellDbIn::start_up() {
|
||||
cell_db_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_).move_as_ok());
|
||||
|
||||
boc_ = vm::DynamicBagOfCellsDb::create();
|
||||
boc_->set_loader(std::make_unique<vm::CellLoader>(cell_db_->snapshot())).ensure();
|
||||
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
|
||||
|
||||
alarm_timestamp() = td::Timestamp::in(10.0);
|
||||
|
||||
auto empty = get_empty_key_hash();
|
||||
if (get_block(empty).is_error()) {
|
||||
DbEntry e{get_empty_key(), empty, empty, RootHash::zero()};
|
||||
cell_db_->begin_transaction().ensure();
|
||||
set_block(empty, std::move(e));
|
||||
cell_db_->commit_transaction().ensure();
|
||||
}
|
||||
last_gc_ = empty;
|
||||
}
|
||||
|
||||
void CellDbIn::load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise) {
|
||||
td::PerfWarningTimer{"loadcell", 0.1};
|
||||
promise.set_result(boc_->load_cell(hash.as_slice()));
|
||||
}
|
||||
|
||||
void CellDbIn::store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise) {
|
||||
td::PerfWarningTimer{"storecell", 0.1};
|
||||
auto key_hash = get_key_hash(block_id);
|
||||
auto R = get_block(key_hash);
|
||||
// duplicate
|
||||
if (R.is_ok()) {
|
||||
promise.set_result(boc_->load_cell(cell->get_hash().as_slice()));
|
||||
return;
|
||||
}
|
||||
|
||||
auto empty = get_empty_key_hash();
|
||||
auto ER = get_block(empty);
|
||||
ER.ensure();
|
||||
auto E = ER.move_as_ok();
|
||||
|
||||
auto PR = get_block(E.prev);
|
||||
PR.ensure();
|
||||
auto P = PR.move_as_ok();
|
||||
CHECK(P.next == empty);
|
||||
|
||||
DbEntry D{block_id, E.prev, empty, cell->get_hash().bits()};
|
||||
|
||||
E.prev = key_hash;
|
||||
P.next = key_hash;
|
||||
|
||||
if (P.is_empty()) {
|
||||
E.next = key_hash;
|
||||
P.prev = key_hash;
|
||||
}
|
||||
|
||||
boc_->inc(cell);
|
||||
boc_->prepare_commit().ensure();
|
||||
vm::CellStorer stor{*cell_db_.get()};
|
||||
cell_db_->begin_transaction().ensure();
|
||||
boc_->commit(stor).ensure();
|
||||
set_block(empty, std::move(E));
|
||||
set_block(D.prev, std::move(P));
|
||||
set_block(key_hash, std::move(D));
|
||||
cell_db_->commit_transaction().ensure();
|
||||
|
||||
boc_->set_loader(std::make_unique<vm::CellLoader>(cell_db_->snapshot())).ensure();
|
||||
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
|
||||
|
||||
promise.set_result(boc_->load_cell(cell->get_hash().as_slice()));
|
||||
}
|
||||
|
||||
void CellDbIn::alarm() {
|
||||
auto R = get_block(last_gc_);
|
||||
R.ensure();
|
||||
|
||||
auto N = R.move_as_ok();
|
||||
if (N.is_empty()) {
|
||||
last_gc_ = N.next;
|
||||
alarm_timestamp() = td::Timestamp::in(0.1);
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CellDbIn::skip_gc);
|
||||
} else {
|
||||
auto value = R.move_as_ok();
|
||||
if (!value) {
|
||||
td::actor::send_closure(SelfId, &CellDbIn::skip_gc);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CellDbIn::gc);
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(root_db_, &RootDb::allow_state_gc, N.block_id, std::move(P));
|
||||
}
|
||||
|
||||
void CellDbIn::gc() {
|
||||
auto R = get_block(last_gc_);
|
||||
R.ensure();
|
||||
|
||||
auto N = R.move_as_ok();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &CellDbIn::gc_cont, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(root_db_, &RootDb::get_block_handle_external, N.block_id, false, std::move(P));
|
||||
}
|
||||
|
||||
void CellDbIn::gc_cont(BlockHandle handle) {
|
||||
CHECK(handle->inited_state_boc());
|
||||
handle->set_deleted_state_boc();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &CellDbIn::gc_cont2, handle);
|
||||
});
|
||||
|
||||
td::actor::send_closure(root_db_, &RootDb::store_block_handle, handle, std::move(P));
|
||||
}
|
||||
|
||||
void CellDbIn::gc_cont2(BlockHandle handle) {
|
||||
td::PerfWarningTimer{"gccell", 0.1};
|
||||
|
||||
auto FR = get_block(last_gc_);
|
||||
FR.ensure();
|
||||
auto F = FR.move_as_ok();
|
||||
|
||||
auto PR = get_block(F.prev);
|
||||
PR.ensure();
|
||||
auto P = PR.move_as_ok();
|
||||
auto NR = get_block(F.next);
|
||||
NR.ensure();
|
||||
auto N = NR.move_as_ok();
|
||||
|
||||
P.next = F.next;
|
||||
N.prev = F.prev;
|
||||
if (P.is_empty() && N.is_empty()) {
|
||||
P.prev = P.next;
|
||||
N.next = N.prev;
|
||||
}
|
||||
|
||||
auto cell = boc_->load_cell(F.root_hash.as_slice()).move_as_ok();
|
||||
|
||||
boc_->dec(cell);
|
||||
boc_->prepare_commit().ensure();
|
||||
vm::CellStorer stor{*cell_db_.get()};
|
||||
cell_db_->begin_transaction().ensure();
|
||||
boc_->commit(stor).ensure();
|
||||
cell_db_->erase(get_key(last_gc_)).ensure();
|
||||
set_block(F.prev, std::move(P));
|
||||
set_block(F.next, std::move(N));
|
||||
cell_db_->commit_transaction().ensure();
|
||||
alarm_timestamp() = td::Timestamp::now();
|
||||
|
||||
boc_->set_loader(std::make_unique<vm::CellLoader>(cell_db_->snapshot())).ensure();
|
||||
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
|
||||
|
||||
DCHECK(get_block(last_gc_).is_error());
|
||||
last_gc_ = F.next;
|
||||
}
|
||||
|
||||
void CellDbIn::skip_gc() {
|
||||
auto FR = get_block(last_gc_);
|
||||
FR.ensure();
|
||||
auto F = FR.move_as_ok();
|
||||
last_gc_ = F.next;
|
||||
alarm_timestamp() = td::Timestamp::in(0.01);
|
||||
}
|
||||
|
||||
std::string CellDbIn::get_key(KeyHash key_hash) {
|
||||
if (!key_hash.is_zero()) {
|
||||
return PSTRING() << "desc" << key_hash;
|
||||
} else {
|
||||
return "desczero";
|
||||
}
|
||||
}
|
||||
|
||||
CellDbIn::KeyHash CellDbIn::get_key_hash(BlockIdExt block_id) {
|
||||
if (block_id.is_valid()) {
|
||||
return get_tl_object_sha_bits256(create_tl_block_id(block_id));
|
||||
} else {
|
||||
return KeyHash::zero();
|
||||
}
|
||||
}
|
||||
|
||||
BlockIdExt CellDbIn::get_empty_key() {
|
||||
return BlockIdExt{workchainInvalid, 0, 0, RootHash::zero(), FileHash::zero()};
|
||||
}
|
||||
|
||||
CellDbIn::KeyHash CellDbIn::get_empty_key_hash() {
|
||||
return KeyHash::zero();
|
||||
}
|
||||
|
||||
td::Result<CellDbIn::DbEntry> CellDbIn::get_block(KeyHash key_hash) {
|
||||
const auto key = get_key(key_hash);
|
||||
std::string value;
|
||||
auto R = cell_db_->get(td::as_slice(key), value);
|
||||
R.ensure();
|
||||
auto S = R.move_as_ok();
|
||||
if (S == td::KeyValue::GetStatus::NotFound) {
|
||||
return td::Status::Error(ErrorCode::notready, "not in db");
|
||||
}
|
||||
auto obj = fetch_tl_object<ton_api::db_celldb_value>(td::BufferSlice{value}, true);
|
||||
obj.ensure();
|
||||
return DbEntry{obj.move_as_ok()};
|
||||
}
|
||||
|
||||
void CellDbIn::set_block(KeyHash key_hash, DbEntry e) {
|
||||
const auto key = get_key(key_hash);
|
||||
cell_db_->set(td::as_slice(key), e.release()).ensure();
|
||||
}
|
||||
|
||||
void CellDb::load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise) {
|
||||
if (!started_) {
|
||||
td::actor::send_closure(cell_db_, &CellDbIn::load_cell, hash, std::move(promise));
|
||||
} else {
|
||||
auto R = boc_->load_cell(hash.as_slice());
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(cell_db_, &CellDbIn::load_cell, hash, std::move(promise));
|
||||
} else {
|
||||
promise.set_result(R.move_as_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CellDb::store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise) {
|
||||
td::actor::send_closure(cell_db_, &CellDbIn::store_cell, block_id, std::move(cell), std::move(promise));
|
||||
}
|
||||
|
||||
void CellDb::start_up() {
|
||||
boc_ = vm::DynamicBagOfCellsDb::create();
|
||||
cell_db_ = td::actor::create_actor<CellDbIn>("celldbin", root_db_, actor_id(this), path_);
|
||||
}
|
||||
|
||||
CellDbIn::DbEntry::DbEntry(tl_object_ptr<ton_api::db_celldb_value> entry)
|
||||
: block_id(create_block_id(entry->block_id_))
|
||||
, prev(entry->prev_)
|
||||
, next(entry->next_)
|
||||
, root_hash(entry->root_hash_) {
|
||||
}
|
||||
|
||||
td::BufferSlice CellDbIn::DbEntry::release() {
|
||||
return create_serialize_tl_object<ton_api::db_celldb_value>(create_tl_block_id(block_id), prev, next, root_hash);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
117
validator/db/celldb.hpp
Normal file
117
validator/db/celldb.hpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "crypto/vm/db/DynamicBagOfCellsDb.h"
|
||||
#include "crypto/vm/db/CellStorage.h"
|
||||
#include "td/db/KeyValue.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "interfaces/block-handle.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb;
|
||||
|
||||
class CellDb;
|
||||
|
||||
class CellDbIn : public td::actor::Actor {
|
||||
public:
|
||||
using KeyHash = td::Bits256;
|
||||
|
||||
void load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise);
|
||||
void store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise);
|
||||
|
||||
CellDbIn(td::actor::ActorId<RootDb> root_db, td::actor::ActorId<CellDb> parent, std::string path);
|
||||
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
|
||||
private:
|
||||
struct DbEntry {
|
||||
BlockIdExt block_id;
|
||||
KeyHash prev;
|
||||
KeyHash next;
|
||||
RootHash root_hash;
|
||||
|
||||
DbEntry(tl_object_ptr<ton_api::db_celldb_value> entry);
|
||||
DbEntry() {
|
||||
}
|
||||
DbEntry(BlockIdExt block_id, KeyHash prev, KeyHash next, RootHash root_hash)
|
||||
: block_id(block_id), prev(prev), next(next), root_hash(root_hash) {
|
||||
}
|
||||
td::BufferSlice release();
|
||||
bool is_empty() const {
|
||||
return !block_id.is_valid();
|
||||
}
|
||||
};
|
||||
td::Result<DbEntry> get_block(KeyHash key);
|
||||
void set_block(KeyHash key, DbEntry e);
|
||||
|
||||
static std::string get_key(KeyHash key);
|
||||
static KeyHash get_key_hash(BlockIdExt block_id);
|
||||
static BlockIdExt get_empty_key();
|
||||
KeyHash get_empty_key_hash();
|
||||
|
||||
void gc();
|
||||
void gc_cont(BlockHandle handle);
|
||||
void gc_cont2(BlockHandle handle);
|
||||
void skip_gc();
|
||||
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
td::actor::ActorId<CellDb> parent_;
|
||||
|
||||
std::string path_;
|
||||
|
||||
std::unique_ptr<vm::DynamicBagOfCellsDb> boc_;
|
||||
std::shared_ptr<vm::KeyValue> cell_db_;
|
||||
|
||||
KeyHash last_gc_;
|
||||
};
|
||||
|
||||
class CellDb : public td::actor::Actor {
|
||||
public:
|
||||
void load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise);
|
||||
void store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise);
|
||||
void update_snapshot(std::unique_ptr<td::KeyValueReader> snapshot) {
|
||||
started_ = true;
|
||||
boc_->set_loader(std::make_unique<vm::CellLoader>(std::move(snapshot))).ensure();
|
||||
}
|
||||
|
||||
CellDb(td::actor::ActorId<RootDb> root_db, std::string path) : root_db_(root_db), path_(path) {
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
|
||||
private:
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
std::string path_;
|
||||
|
||||
td::actor::ActorOwn<CellDbIn> cell_db_;
|
||||
|
||||
std::unique_ptr<vm::DynamicBagOfCellsDb> boc_;
|
||||
bool started_ = false;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
333
validator/db/filedb.cpp
Normal file
333
validator/db/filedb.cpp
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "filedb.hpp"
|
||||
#include "rootdb.hpp"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "files-async.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
#include "td/db/RocksDb.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
std::string FileDb::get_file_name(const RefId& ref_id, bool create_dirs) {
|
||||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
|
||||
auto s = ref_id_hash.to_hex();
|
||||
if (create_dirs) {
|
||||
td::mkdir(root_path_ + "/files/" + s[0] + s[1] + "/").ensure();
|
||||
td::mkdir(root_path_ + "/files/" + s[0] + s[1] + "/" + s[2] + s[3] + "/").ensure();
|
||||
}
|
||||
return root_path_ + "/files/" + s[0] + s[1] + "/" + s[2] + s[3] + "/" + s;
|
||||
}
|
||||
|
||||
void FileDb::store_file(RefId ref_id, td::BufferSlice data, td::Promise<FileHash> promise) {
|
||||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
auto R = get_block(ref_id_hash);
|
||||
if (R.is_ok()) {
|
||||
auto val = R.move_as_ok();
|
||||
promise.set_result(val.file_hash);
|
||||
return;
|
||||
}
|
||||
|
||||
auto file_hash = sha256_bits256(data.as_slice());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), file_hash, ref_id = std::move(ref_id),
|
||||
promise = std::move(promise)](td::Result<std::string> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FileDb::store_file_continue, std::move(ref_id), file_hash, R.move_as_ok(),
|
||||
std::move(promise));
|
||||
}
|
||||
});
|
||||
td::actor::create_actor<db::WriteFile>("writefile", root_path_ + "/tmp/", "", std::move(data), std::move(P))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FileDb::store_file_continue(RefId ref_id, FileHash file_hash, std::string res_path,
|
||||
td::Promise<FileHash> promise) {
|
||||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
auto R = get_block(ref_id_hash);
|
||||
if (R.is_ok()) {
|
||||
td::unlink(res_path).ignore();
|
||||
auto val = R.move_as_ok();
|
||||
promise.set_result(val.file_hash);
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = get_file_name(ref_id, true);
|
||||
td::rename(res_path, path).ensure();
|
||||
|
||||
auto empty = get_empty_ref_id_hash();
|
||||
auto ER = get_block(empty);
|
||||
ER.ensure();
|
||||
auto E = ER.move_as_ok();
|
||||
|
||||
auto PR = get_block(E.prev);
|
||||
PR.ensure();
|
||||
auto P = PR.move_as_ok();
|
||||
CHECK(P.next == empty);
|
||||
|
||||
DbEntry D;
|
||||
D.key = std::move(ref_id);
|
||||
D.prev = E.prev;
|
||||
D.next = empty;
|
||||
D.file_hash = file_hash;
|
||||
|
||||
E.prev = ref_id_hash;
|
||||
P.next = ref_id_hash;
|
||||
|
||||
if (P.is_empty()) {
|
||||
E.next = ref_id_hash;
|
||||
P.prev = ref_id_hash;
|
||||
}
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
set_block(empty, std::move(E));
|
||||
set_block(D.prev, std::move(P));
|
||||
set_block(ref_id_hash, std::move(D));
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(std::move(file_hash));
|
||||
}
|
||||
|
||||
void FileDb::load_file(RefId ref_id, td::Promise<td::BufferSlice> promise) {
|
||||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
auto R = get_block(ref_id_hash);
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto v = R.move_as_ok();
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise), file_hash = v.file_hash](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
auto data = R.move_as_ok();
|
||||
if (file_hash != sha256_bits256(data.as_slice())) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "db error: bad file hash"));
|
||||
} else {
|
||||
promise.set_value(std::move(data));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), std::move(P)).release();
|
||||
}
|
||||
|
||||
void FileDb::check_file(RefId ref_id, td::Promise<bool> promise) {
|
||||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
auto R = get_block(ref_id_hash);
|
||||
if (R.is_error()) {
|
||||
promise.set_result(false);
|
||||
return;
|
||||
}
|
||||
promise.set_result(true);
|
||||
}
|
||||
|
||||
td::Slice FileDb::get_key(const RefIdHash& ref) {
|
||||
return ref.as_slice();
|
||||
}
|
||||
|
||||
td::Result<FileDb::DbEntry> FileDb::get_block(const RefIdHash& ref) {
|
||||
std::string value;
|
||||
auto R = kv_->get(get_key(ref), value);
|
||||
R.ensure();
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
return td::Status::Error(ErrorCode::notready, "not in db");
|
||||
}
|
||||
auto val = fetch_tl_object<ton_api::db_filedb_value>(td::BufferSlice{value}, true);
|
||||
val.ensure();
|
||||
return DbEntry{val.move_as_ok()};
|
||||
}
|
||||
|
||||
void FileDb::set_block(const RefIdHash& ref, DbEntry entry) {
|
||||
DCHECK(ref == get_ref_id_hash(entry.key));
|
||||
kv_->set(get_key(ref), entry.release()).ensure();
|
||||
}
|
||||
|
||||
FileDb::FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, bool is_archive)
|
||||
: root_db_(root_db), root_path_(root_path), is_archive_(is_archive) {
|
||||
}
|
||||
|
||||
void FileDb::start_up() {
|
||||
td::mkdir(root_path_).ensure();
|
||||
db_path_ = root_path_ + "/db/";
|
||||
|
||||
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
|
||||
td::mkdir(root_path_ + "/files/").ensure();
|
||||
td::mkdir(root_path_ + "/tmp/").ensure();
|
||||
|
||||
last_gc_ = get_empty_ref_id_hash();
|
||||
alarm_timestamp() = td::Timestamp::in(0.01);
|
||||
|
||||
auto R = get_block(last_gc_);
|
||||
if (R.is_error()) {
|
||||
DbEntry e{get_empty_ref_id(), last_gc_, last_gc_, FileHash::zero()};
|
||||
kv_->begin_transaction().ensure();
|
||||
set_block(last_gc_, std::move(e));
|
||||
kv_->commit_transaction().ensure();
|
||||
}
|
||||
}
|
||||
|
||||
void FileDb::alarm() {
|
||||
auto R = get_block(last_gc_);
|
||||
R.ensure();
|
||||
auto N = R.move_as_ok();
|
||||
if (N.is_empty()) {
|
||||
last_gc_ = N.next;
|
||||
alarm_timestamp() = td::Timestamp::in(0.01);
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) mutable {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FileDb::skip_gc);
|
||||
} else {
|
||||
auto value = R.move_as_ok();
|
||||
if (!value) {
|
||||
td::actor::send_closure(SelfId, &FileDb::skip_gc);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FileDb::gc);
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(root_db_, &RootDb::allow_gc, std::move(N.key), is_archive_, std::move(P));
|
||||
}
|
||||
|
||||
void FileDb::gc() {
|
||||
auto FR = get_block(last_gc_);
|
||||
FR.ensure();
|
||||
auto F = FR.move_as_ok();
|
||||
|
||||
auto PR = get_block(F.prev);
|
||||
PR.ensure();
|
||||
auto P = PR.move_as_ok();
|
||||
auto NR = get_block(F.next);
|
||||
NR.ensure();
|
||||
auto N = NR.move_as_ok();
|
||||
|
||||
P.next = F.next;
|
||||
N.prev = F.prev;
|
||||
if (P.is_empty() && N.is_empty()) {
|
||||
P.prev = P.next;
|
||||
N.next = N.prev;
|
||||
}
|
||||
|
||||
auto name = get_file_name(F.key, false);
|
||||
auto S = td::unlink(name);
|
||||
if (S.is_error()) {
|
||||
LOG(WARNING) << "failed to delete " << name;
|
||||
}
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->erase(last_gc_.as_slice()).ensure();
|
||||
set_block(F.prev, std::move(P));
|
||||
set_block(F.next, std::move(N));
|
||||
kv_->commit_transaction().ensure();
|
||||
alarm_timestamp() = td::Timestamp::now();
|
||||
|
||||
DCHECK(get_block(last_gc_).is_error());
|
||||
last_gc_ = F.next;
|
||||
}
|
||||
|
||||
void FileDb::skip_gc() {
|
||||
auto FR = get_block(last_gc_);
|
||||
FR.ensure();
|
||||
auto F = FR.move_as_ok();
|
||||
last_gc_ = F.next;
|
||||
alarm_timestamp() = td::Timestamp::in(0.01);
|
||||
}
|
||||
|
||||
td::BufferSlice FileDb::DbEntry::release() {
|
||||
return create_serialize_tl_object<ton_api::db_filedb_value>(get_ref_id_tl(key), prev, next, file_hash);
|
||||
}
|
||||
|
||||
bool FileDb::DbEntry::is_empty() const {
|
||||
return (key.get_offset() == key.offset<fileref::Empty>());
|
||||
}
|
||||
|
||||
FileDb::RefIdHash FileDb::get_ref_id_hash(const RefId& ref) {
|
||||
FileHash x;
|
||||
ref.visit([&](const auto& obj) { x = obj.hash(); });
|
||||
return x;
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::db_filedb_Key> FileDb::get_ref_id_tl(const RefId& ref) {
|
||||
tl_object_ptr<ton_api::db_filedb_Key> x;
|
||||
ref.visit([&](const auto& obj) { x = obj.tl(); });
|
||||
return x;
|
||||
}
|
||||
|
||||
FileDb::RefId FileDb::get_ref_from_tl(const ton_api::db_filedb_Key& from) {
|
||||
RefId ref_id{fileref::Empty{}};
|
||||
ton_api::downcast_call(
|
||||
const_cast<ton_api::db_filedb_Key&>(from),
|
||||
td::overloaded(
|
||||
[&](const ton_api::db_filedb_key_empty& key) { ref_id = fileref::Empty{}; },
|
||||
[&](const ton_api::db_filedb_key_blockFile& key) { ref_id = fileref::Block{create_block_id(key.block_id_)}; },
|
||||
[&](const ton_api::db_filedb_key_zeroStateFile& key) {
|
||||
ref_id = fileref::ZeroState{create_block_id(key.block_id_)};
|
||||
},
|
||||
[&](const ton_api::db_filedb_key_persistentStateFile& key) {
|
||||
ref_id =
|
||||
fileref::PersistentState{create_block_id(key.block_id_), create_block_id(key.masterchain_block_id_)};
|
||||
},
|
||||
[&](const ton_api::db_filedb_key_proof& key) { ref_id = fileref::Proof{create_block_id(key.block_id_)}; },
|
||||
[&](const ton_api::db_filedb_key_proofLink& key) {
|
||||
ref_id = fileref::ProofLink{create_block_id(key.block_id_)};
|
||||
},
|
||||
[&](const ton_api::db_filedb_key_signatures& key) {
|
||||
ref_id = fileref::Signatures{create_block_id(key.block_id_)};
|
||||
},
|
||||
[&](const ton_api::db_filedb_key_candidate& key) {
|
||||
ref_id = fileref::Candidate{PublicKey{key.id_->source_}, create_block_id(key.id_->id_),
|
||||
key.id_->collated_data_file_hash_};
|
||||
}));
|
||||
return ref_id;
|
||||
}
|
||||
|
||||
FileDb::RefId FileDb::get_empty_ref_id() {
|
||||
return fileref::Empty();
|
||||
}
|
||||
|
||||
FileDb::RefIdHash FileDb::get_empty_ref_id_hash() {
|
||||
if (empty_.is_zero()) {
|
||||
empty_ = get_ref_id_hash(get_empty_ref_id());
|
||||
}
|
||||
return empty_;
|
||||
}
|
||||
|
||||
FileDb::DbEntry::DbEntry(tl_object_ptr<ton_api::db_filedb_value> entry)
|
||||
: key(FileDb::get_ref_from_tl(*entry->key_.get()))
|
||||
, prev(entry->prev_)
|
||||
, next(entry->next_)
|
||||
, file_hash(entry->file_hash_) {
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
202
validator/db/filedb.hpp
Normal file
202
validator/db/filedb.hpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "td/actor/actor.h"
|
||||
#include "validator/interfaces/shard.h"
|
||||
#include "td/db/KeyValue.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fileref {
|
||||
|
||||
class Empty {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_empty>();
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_empty>();
|
||||
}
|
||||
};
|
||||
|
||||
class Block {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_blockFile>(create_tl_block_id(block_id));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_blockFile>(create_tl_block_id(block_id));
|
||||
}
|
||||
|
||||
BlockIdExt block_id;
|
||||
};
|
||||
|
||||
class ZeroState {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_zeroStateFile>(create_tl_block_id(block_id));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_zeroStateFile>(create_tl_block_id(block_id));
|
||||
}
|
||||
|
||||
BlockIdExt block_id;
|
||||
};
|
||||
|
||||
class PersistentState {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_persistentStateFile>(create_tl_block_id(block_id),
|
||||
create_tl_block_id(masterchain_block_id));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_persistentStateFile>(create_tl_block_id(block_id),
|
||||
create_tl_block_id(masterchain_block_id));
|
||||
}
|
||||
|
||||
BlockIdExt block_id;
|
||||
BlockIdExt masterchain_block_id;
|
||||
};
|
||||
|
||||
class Proof {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_proof>(create_tl_block_id(block_id));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_proof>(create_tl_block_id(block_id));
|
||||
}
|
||||
|
||||
BlockIdExt block_id;
|
||||
};
|
||||
|
||||
class ProofLink {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_proofLink>(create_tl_block_id(block_id));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_proofLink>(create_tl_block_id(block_id));
|
||||
}
|
||||
|
||||
BlockIdExt block_id;
|
||||
};
|
||||
|
||||
class Signatures {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_signatures>(create_tl_block_id(block_id));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_signatures>(create_tl_block_id(block_id));
|
||||
}
|
||||
|
||||
BlockIdExt block_id;
|
||||
};
|
||||
|
||||
class Candidate {
|
||||
public:
|
||||
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
|
||||
return create_tl_object<ton_api::db_filedb_key_candidate>(
|
||||
create_tl_object<ton_api::db_candidate_id>(source.tl(), create_tl_block_id(block_id), collated_data_file_hash));
|
||||
}
|
||||
FileHash hash() const {
|
||||
return create_hash_tl_object<ton_api::db_filedb_key_candidate>(
|
||||
create_tl_object<ton_api::db_candidate_id>(source.tl(), create_tl_block_id(block_id), collated_data_file_hash));
|
||||
}
|
||||
|
||||
PublicKey source;
|
||||
BlockIdExt block_id;
|
||||
FileHash collated_data_file_hash;
|
||||
};
|
||||
}; // namespace fileref
|
||||
|
||||
class RootDb;
|
||||
|
||||
class FileDb : public td::actor::Actor {
|
||||
public:
|
||||
using RefId =
|
||||
td::Variant<fileref::Empty, fileref::Block, fileref::ZeroState, fileref::PersistentState, fileref::Proof,
|
||||
fileref::Proof, fileref::ProofLink, fileref::Signatures, fileref::Candidate>;
|
||||
using RefIdHash = td::Bits256;
|
||||
|
||||
void store_file(RefId ref_id, td::BufferSlice data, td::Promise<FileHash> promise);
|
||||
void store_file_continue(RefId ref_id, FileHash file_hash, std::string path, td::Promise<FileHash> promise);
|
||||
void load_file(RefId ref_id, td::Promise<td::BufferSlice> promise);
|
||||
void check_file(RefId ref_id, td::Promise<bool> promise);
|
||||
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
|
||||
void gc();
|
||||
void skip_gc();
|
||||
|
||||
FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, bool is_archive);
|
||||
|
||||
private:
|
||||
struct DbEntry {
|
||||
RefId key;
|
||||
RefIdHash prev;
|
||||
RefIdHash next;
|
||||
FileHash file_hash;
|
||||
|
||||
DbEntry(tl_object_ptr<ton_api::db_filedb_value> entry);
|
||||
DbEntry() {
|
||||
}
|
||||
DbEntry(RefId key, RefIdHash prev, RefIdHash next, FileHash file_hash)
|
||||
: key(std::move(key)), prev(prev), next(next), file_hash(file_hash) {
|
||||
}
|
||||
td::BufferSlice release();
|
||||
bool is_empty() const;
|
||||
};
|
||||
|
||||
static RefIdHash get_ref_id_hash(const RefId& ref);
|
||||
static tl_object_ptr<ton_api::db_filedb_Key> get_ref_id_tl(const RefId& ref);
|
||||
static RefId get_ref_from_tl(const ton_api::db_filedb_Key& from);
|
||||
static RefId get_empty_ref_id();
|
||||
RefIdHash get_empty_ref_id_hash();
|
||||
|
||||
std::string get_file_name(const RefId& ref, bool create_dirs);
|
||||
td::Slice get_key(const RefIdHash& ref);
|
||||
|
||||
td::Result<DbEntry> get_block(const RefIdHash& ref_id);
|
||||
void set_block(const RefIdHash& ref_id_hash, DbEntry entry);
|
||||
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
|
||||
std::string root_path_;
|
||||
std::string db_path_;
|
||||
|
||||
bool is_archive_;
|
||||
|
||||
std::shared_ptr<td::KeyValue> kv_;
|
||||
|
||||
RefIdHash last_gc_;
|
||||
RefIdHash empty_ = RefIdHash::zero();
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
||||
108
validator/db/files-async.hpp
Normal file
108
validator/db/files-async.hpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/buffer.h"
|
||||
|
||||
#include "common/errorcode.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace db {
|
||||
|
||||
class WriteFile : public td::actor::Actor {
|
||||
public:
|
||||
void start_up() override {
|
||||
auto R = [&]() {
|
||||
td::uint32 cnt = 0;
|
||||
while (true) {
|
||||
cnt++;
|
||||
auto res = td::mkstemp(td::CSlice{tmp_dir_});
|
||||
if (res.is_ok() || cnt >= 10) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}();
|
||||
if (R.is_error()) {
|
||||
promise_.set_error(R.move_as_error());
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
auto res = R.move_as_ok();
|
||||
auto file = std::move(res.first);
|
||||
auto old_name = res.second;
|
||||
size_t offset = 0;
|
||||
while (data_.size() > 0) {
|
||||
auto R = file.pwrite(data_.as_slice(), offset);
|
||||
auto s = R.move_as_ok();
|
||||
offset += s;
|
||||
data_.confirm_read(s);
|
||||
}
|
||||
file.sync().ensure();
|
||||
if (new_name_.length() > 0) {
|
||||
td::rename(old_name, new_name_).ensure();
|
||||
promise_.set_value(std::move(new_name_));
|
||||
} else {
|
||||
promise_.set_value(std::move(old_name));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
WriteFile(std::string tmp_dir, std::string new_name, td::BufferSlice data, td::Promise<std::string> promise)
|
||||
: tmp_dir_(tmp_dir), new_name_(new_name), data_(std::move(data)), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string tmp_dir_;
|
||||
std::string new_name_;
|
||||
td::BufferSlice data_;
|
||||
td::Promise<std::string> promise_;
|
||||
};
|
||||
|
||||
class ReadFile : public td::actor::Actor {
|
||||
public:
|
||||
void start_up() override {
|
||||
auto S = td::read_file(file_name_);
|
||||
if (S.is_ok()) {
|
||||
promise_.set_result(S.move_as_ok());
|
||||
} else {
|
||||
// TODO check error code
|
||||
LOG(ERROR) << "missing file " << file_name_;
|
||||
promise_.set_error(td::Status::Error(ErrorCode::notready, "file does not exist"));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
ReadFile(std::string file_name, td::Promise<td::BufferSlice> promise)
|
||||
: file_name_(file_name), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string file_name_;
|
||||
td::Promise<td::BufferSlice> promise_;
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
221
validator/db/ltdb.cpp
Normal file
221
validator/db/ltdb.cpp
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "ltdb.hpp"
|
||||
#include "rootdb.hpp"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "td/db/RocksDb.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void LtDb::add_new_block(BlockIdExt block_id, LogicalTime lt, UnixTime ts, td::Promise<td::Unit> promise) {
|
||||
auto key = get_desc_key(block_id.shard_full());
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(key.as_slice(), value);
|
||||
R.ensure();
|
||||
tl_object_ptr<ton_api::db_lt_desc_value> v;
|
||||
bool add_shard = false;
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::Ok) {
|
||||
auto F = fetch_tl_object<ton_api::db_lt_desc_value>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
v = F.move_as_ok();
|
||||
} else {
|
||||
v = create_tl_object<ton_api::db_lt_desc_value>(1, 1, 0, 0, 0);
|
||||
add_shard = true;
|
||||
}
|
||||
if (block_id.id.seqno <= static_cast<td::uint32>(v->last_seqno_) || lt <= static_cast<LogicalTime>(v->last_lt_) ||
|
||||
ts <= static_cast<UnixTime>(v->last_ts_)) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
auto db_value = create_serialize_tl_object<ton_api::db_lt_el_value>(create_tl_block_id(block_id), lt, ts);
|
||||
auto db_key = get_el_key(block_id.shard_full(), v->last_idx_++);
|
||||
auto status_key = create_serialize_tl_object<ton_api::db_lt_status_key>();
|
||||
v->last_seqno_ = block_id.id.seqno;
|
||||
v->last_lt_ = lt;
|
||||
v->last_ts_ = ts;
|
||||
|
||||
td::uint32 idx = 0;
|
||||
if (add_shard) {
|
||||
auto G = kv_->get(status_key.as_slice(), value);
|
||||
G.ensure();
|
||||
if (G.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
idx = 0;
|
||||
} else {
|
||||
auto F = fetch_tl_object<ton_api::db_lt_status_value>(value, true);
|
||||
F.ensure();
|
||||
auto f = F.move_as_ok();
|
||||
idx = f->total_shards_;
|
||||
}
|
||||
}
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(key, serialize_tl_object(v, true)).ensure();
|
||||
kv_->set(db_key, db_value.as_slice()).ensure();
|
||||
if (add_shard) {
|
||||
auto shard_key = create_serialize_tl_object<ton_api::db_lt_shard_key>(idx);
|
||||
auto shard_value = create_serialize_tl_object<ton_api::db_lt_shard_value>(block_id.id.workchain, block_id.id.shard);
|
||||
kv_->set(status_key.as_slice(), create_serialize_tl_object<ton_api::db_lt_status_value>(idx + 1)).ensure();
|
||||
kv_->set(shard_key.as_slice(), shard_value.as_slice()).ensure();
|
||||
}
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void LtDb::get_block_common(AccountIdPrefixFull account_id,
|
||||
std::function<td::int32(ton_api::db_lt_desc_value &)> compare_desc,
|
||||
std::function<td::int32(ton_api::db_lt_el_value &)> compare, bool exact,
|
||||
td::Promise<BlockIdExt> promise) {
|
||||
bool f = false;
|
||||
BlockIdExt block_id;
|
||||
td::uint32 ls = 0;
|
||||
for (td::uint32 len = 0; len <= 60; len++) {
|
||||
auto s = shard_prefix(account_id, len);
|
||||
auto key = get_desc_key(s);
|
||||
std::string value;
|
||||
auto F = kv_->get(key, value);
|
||||
F.ensure();
|
||||
if (F.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
if (!f) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
f = true;
|
||||
auto G = fetch_tl_object<ton_api::db_lt_desc_value>(td::BufferSlice{value}, true);
|
||||
G.ensure();
|
||||
auto g = G.move_as_ok();
|
||||
if (compare_desc(*g.get()) > 0) {
|
||||
continue;
|
||||
}
|
||||
td::uint32 l = g->first_idx_ - 1;
|
||||
BlockIdExt lseq;
|
||||
td::uint32 r = g->last_idx_;
|
||||
BlockIdExt rseq;
|
||||
while (r - l > 1) {
|
||||
auto x = (r + l) / 2;
|
||||
auto db_key = get_el_key(s, x);
|
||||
F = kv_->get(db_key, value);
|
||||
F.ensure();
|
||||
CHECK(F.move_as_ok() == td::KeyValue::GetStatus::Ok);
|
||||
auto E = fetch_tl_object<ton_api::db_lt_el_value>(td::BufferSlice{value}, true);
|
||||
E.ensure();
|
||||
auto e = E.move_as_ok();
|
||||
int cmp_val = compare(*e.get());
|
||||
|
||||
if (cmp_val < 0) {
|
||||
rseq = create_block_id(e->id_);
|
||||
r = x;
|
||||
} else if (cmp_val > 0) {
|
||||
lseq = create_block_id(e->id_);
|
||||
l = x;
|
||||
} else {
|
||||
promise.set_value(create_block_id(e->id_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (rseq.is_valid()) {
|
||||
if (!block_id.is_valid()) {
|
||||
block_id = rseq;
|
||||
} else if (block_id.id.seqno > rseq.id.seqno) {
|
||||
block_id = rseq;
|
||||
}
|
||||
}
|
||||
if (lseq.is_valid()) {
|
||||
if (ls < lseq.id.seqno) {
|
||||
ls = lseq.id.seqno;
|
||||
}
|
||||
}
|
||||
if (block_id.is_valid() && ls + 1 == block_id.id.seqno) {
|
||||
if (!exact) {
|
||||
promise.set_value(std::move(block_id));
|
||||
} else {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "ltdb: block not found"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!exact && block_id.is_valid()) {
|
||||
promise.set_value(std::move(block_id));
|
||||
} else {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "ltdb: block not found"));
|
||||
}
|
||||
}
|
||||
|
||||
void LtDb::get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime lt, td::Promise<BlockIdExt> promise) {
|
||||
return get_block_common(
|
||||
account_id,
|
||||
[lt](ton_api::db_lt_desc_value &w) {
|
||||
return lt > static_cast<LogicalTime>(w.last_lt_) ? 1 : lt == static_cast<LogicalTime>(w.last_lt_) ? 0 : -1;
|
||||
},
|
||||
[lt](ton_api::db_lt_el_value &w) {
|
||||
return lt > static_cast<LogicalTime>(w.lt_) ? 1 : lt == static_cast<LogicalTime>(w.lt_) ? 0 : -1;
|
||||
},
|
||||
false, std::move(promise));
|
||||
}
|
||||
|
||||
void LtDb::get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise) {
|
||||
return get_block_common(
|
||||
account_id,
|
||||
[seqno](ton_api::db_lt_desc_value &w) {
|
||||
return seqno > static_cast<BlockSeqno>(w.last_seqno_)
|
||||
? 1
|
||||
: seqno == static_cast<BlockSeqno>(w.last_seqno_) ? 0 : -1;
|
||||
},
|
||||
[seqno](ton_api::db_lt_el_value &w) {
|
||||
return seqno > static_cast<BlockSeqno>(w.id_->seqno_)
|
||||
? 1
|
||||
: seqno == static_cast<BlockSeqno>(w.id_->seqno_) ? 0 : -1;
|
||||
},
|
||||
true, std::move(promise));
|
||||
}
|
||||
|
||||
void LtDb::get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise) {
|
||||
return get_block_common(
|
||||
account_id,
|
||||
[ts](ton_api::db_lt_desc_value &w) {
|
||||
return ts > static_cast<UnixTime>(w.last_ts_) ? 1 : ts == static_cast<UnixTime>(w.last_ts_) ? 0 : -1;
|
||||
},
|
||||
[ts](ton_api::db_lt_el_value &w) {
|
||||
return ts > static_cast<UnixTime>(w.ts_) ? 1 : ts == static_cast<UnixTime>(w.ts_) ? 0 : -1;
|
||||
},
|
||||
false, std::move(promise));
|
||||
}
|
||||
|
||||
td::BufferSlice LtDb::get_desc_key(ShardIdFull shard) {
|
||||
return create_serialize_tl_object<ton_api::db_lt_desc_key>(shard.workchain, shard.shard);
|
||||
}
|
||||
|
||||
td::BufferSlice LtDb::get_el_key(ShardIdFull shard, td::uint32 idx) {
|
||||
return create_serialize_tl_object<ton_api::db_lt_el_key>(shard.workchain, shard.shard, idx);
|
||||
}
|
||||
|
||||
void LtDb::start_up() {
|
||||
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
63
validator/db/ltdb.hpp
Normal file
63
validator/db/ltdb.hpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/db/KeyValueAsync.h"
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb;
|
||||
|
||||
class LtDb : public td::actor::Actor {
|
||||
public:
|
||||
void add_new_block(BlockIdExt block_id, LogicalTime lt, UnixTime ts, td::Promise<td::Unit> promise);
|
||||
void get_block_common(AccountIdPrefixFull account_id,
|
||||
std::function<td::int32(ton_api::db_lt_desc_value &)> compare_desc,
|
||||
std::function<td::int32(ton_api::db_lt_el_value &)> compare, bool exact,
|
||||
td::Promise<BlockIdExt> promise);
|
||||
void get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime lt, td::Promise<BlockIdExt> promise);
|
||||
void get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise);
|
||||
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise);
|
||||
|
||||
void start_up() override;
|
||||
|
||||
LtDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(std::move(db_path)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::BufferSlice get_desc_key(ShardIdFull shard);
|
||||
td::BufferSlice get_el_key(ShardIdFull shard, td::uint32 idx);
|
||||
td::BufferSlice get_from_db(ShardIdFull shard, td::uint32 idx);
|
||||
|
||||
std::shared_ptr<td::KeyValue> kv_;
|
||||
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
std::string db_path_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
470
validator/db/rootdb.cpp
Normal file
470
validator/db/rootdb.cpp
Normal file
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "rootdb.hpp"
|
||||
#include "validator/fabric.h"
|
||||
#include "archiver.hpp"
|
||||
|
||||
#include "td/db/RocksDb.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "common/checksum.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void RootDb::store_block_data(BlockHandle handle, td::Ref<BlockData> block, td::Promise<td::Unit> promise) {
|
||||
if (handle->moved_to_storage()) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
auto id = block_db_.get();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
handle->set_received();
|
||||
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::Block{handle->id()}}, block->data(),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_block_data(BlockHandle handle, td::Promise<td::Ref<BlockData>> promise) {
|
||||
if (!handle->received()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[id = handle->id(), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_result(create_block(id, R.move_as_ok()));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(handle->moved_to_storage() ? archive_db_.get() : file_db_.get(), &FileDb::load_file,
|
||||
FileDb::RefId{fileref::Block{handle->id()}}, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::store_block_signatures(BlockHandle handle, td::Ref<BlockSignatureSet> data,
|
||||
td::Promise<td::Unit> promise) {
|
||||
if (handle->moved_to_storage()) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
auto id = block_db_.get();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
handle->set_signatures();
|
||||
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::Signatures{handle->id()}},
|
||||
data->serialize(), std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockSignatureSet>> promise) {
|
||||
if (!handle->inited_signatures()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
|
||||
} else {
|
||||
if (handle->moved_to_storage()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::error, "signatures already gc'd"));
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_result(create_signature_set(R.move_as_ok()));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Signatures{handle->id()}},
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::store_block_proof(BlockHandle handle, td::Ref<Proof> proof, td::Promise<td::Unit> promise) {
|
||||
if (handle->moved_to_storage()) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
auto id = block_db_.get();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
handle->set_proof();
|
||||
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::Proof{handle->id()}}, proof->data(),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_block_proof(BlockHandle handle, td::Promise<td::Ref<Proof>> promise) {
|
||||
if (!handle->inited_proof()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[id = handle->id(), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_result(create_proof(id, R.move_as_ok()));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(handle->moved_to_storage() ? archive_db_.get() : file_db_.get(), &FileDb::load_file,
|
||||
FileDb::RefId{fileref::Proof{handle->id()}}, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::store_block_proof_link(BlockHandle handle, td::Ref<ProofLink> proof, td::Promise<td::Unit> promise) {
|
||||
if (handle->moved_to_storage()) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
auto id = block_db_.get();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
handle->set_proof_link();
|
||||
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::ProofLink{handle->id()}}, proof->data(),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_block_proof_link(BlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) {
|
||||
if (!handle->inited_proof_link()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[id = handle->id(), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_result(create_proof_link(id, R.move_as_ok()));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(handle->moved_to_storage() ? archive_db_.get() : file_db_.get(), &FileDb::load_file,
|
||||
FileDb::RefId{fileref::ProofLink{handle->id()}}, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) {
|
||||
auto obj = create_serialize_tl_object<ton_api::db_candidate>(
|
||||
PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}.tl(), create_tl_block_id(candidate.id),
|
||||
std::move(candidate.data), std::move(candidate.collated_data));
|
||||
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(file_db_, &FileDb::store_file,
|
||||
FileDb::RefId{fileref::Candidate{PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}},
|
||||
candidate.id, candidate.collated_file_hash}},
|
||||
std::move(obj), std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
auto f = fetch_tl_object<ton_api::db_candidate>(R.move_as_ok(), true);
|
||||
f.ensure();
|
||||
auto val = f.move_as_ok();
|
||||
auto hash = sha256_bits256(val->collated_data_);
|
||||
|
||||
auto key = ton::PublicKey{val->source_};
|
||||
auto e_key = Ed25519_PublicKey{key.ed25519_value().raw()};
|
||||
promise.set_value(BlockCandidate{e_key, create_block_id(val->id_), hash, std::move(val->data_),
|
||||
std::move(val->collated_data_)});
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(file_db_, &FileDb::load_file,
|
||||
FileDb::RefId{fileref::Candidate{source, id, collated_data_file_hash}}, std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::store_block_state(BlockHandle handle, td::Ref<ShardState> state,
|
||||
td::Promise<td::Ref<ShardState>> promise) {
|
||||
if (handle->moved_to_storage()) {
|
||||
promise.set_value(std::move(state));
|
||||
return;
|
||||
}
|
||||
if (!handle->inited_state_boc()) {
|
||||
auto P = td::PromiseCreator::lambda([b = block_db_.get(), root_hash = state->root_hash(), handle,
|
||||
promise = std::move(promise)](td::Result<td::Ref<vm::DataCell>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
handle->set_state_root_hash(root_hash);
|
||||
handle->set_state_boc();
|
||||
|
||||
auto S = create_shard_state(handle->id(), R.move_as_ok());
|
||||
S.ensure();
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise), state = S.move_as_ok()](td::Result<td::Unit> R) mutable {
|
||||
R.ensure();
|
||||
promise.set_value(std::move(state));
|
||||
});
|
||||
|
||||
td::actor::send_closure(b, &BlockDb::store_block_handle, std::move(handle), std::move(P));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(cell_db_, &CellDb::store_cell, handle->id(), state->root_cell(), std::move(P));
|
||||
} else {
|
||||
get_block_state(handle, std::move(promise));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::get_block_state(BlockHandle handle, td::Promise<td::Ref<ShardState>> promise) {
|
||||
if (handle->inited_state_boc()) {
|
||||
if (handle->deleted_state_boc()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::error, "state already gc'd"));
|
||||
return;
|
||||
}
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([handle, promise = std::move(promise)](td::Result<td::Ref<vm::DataCell>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
auto S = create_shard_state(handle->id(), R.move_as_ok());
|
||||
S.ensure();
|
||||
promise.set_value(S.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(cell_db_, &CellDb::load_cell, handle->state(), std::move(P));
|
||||
} else {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "state not in db"));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::store_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::BufferSlice state,
|
||||
td::Promise<td::Unit> promise) {
|
||||
auto id = block_db_.get();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([id, promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(archive_db_, &FileDb::store_file,
|
||||
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(state),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(archive_db_, &FileDb::load_file,
|
||||
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::check_persistent_state_file_exists(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<bool> promise) {
|
||||
td::actor::send_closure(archive_db_, &FileDb::check_file,
|
||||
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) {
|
||||
auto id = block_db_.get();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([id, promise = std::move(promise)](td::Result<FileHash> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::ZeroState{block_id}},
|
||||
std::move(state), std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_zero_state_file(BlockIdExt block_id, td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(archive_db_, &FileDb::load_file, FileDb::RefId{fileref::ZeroState{block_id}},
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::check_zero_state_file_exists(BlockIdExt block_id, td::Promise<bool> promise) {
|
||||
td::actor::send_closure(archive_db_, &FileDb::check_file, FileDb::RefId{fileref::ZeroState{block_id}},
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(block_db_, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) {
|
||||
td::actor::send_closure(block_db_, &BlockDb::get_block_handle, id, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(static_files_db_, &StaticFilesDb::load_file, file_hash, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::apply_block(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
if (handle->id().id.seqno == 0) {
|
||||
promise.set_value(td::Unit());
|
||||
} else {
|
||||
td::actor::send_closure(lt_db_, &LtDb::add_new_block, handle->id(), handle->logical_time(), handle->unix_time(),
|
||||
std::move(promise));
|
||||
}
|
||||
}
|
||||
|
||||
void RootDb::get_block_by_lt(AccountIdPrefixFull account, LogicalTime lt, td::Promise<BlockIdExt> promise) {
|
||||
td::actor::send_closure(lt_db_, &LtDb::get_block_by_lt, account, lt, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_block_by_unix_time(AccountIdPrefixFull account, UnixTime ts, td::Promise<BlockIdExt> promise) {
|
||||
td::actor::send_closure(lt_db_, &LtDb::get_block_by_unix_time, account, ts, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_block_by_seqno(AccountIdPrefixFull account, BlockSeqno seqno, td::Promise<BlockIdExt> promise) {
|
||||
td::actor::send_closure(lt_db_, &LtDb::get_block_by_seqno, account, seqno, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::update_init_masterchain_block, block, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_init_masterchain_block(td::Promise<BlockIdExt> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::get_init_masterchain_block, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::update_gc_masterchain_block, block, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_gc_masterchain_block(td::Promise<BlockIdExt> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::get_gc_masterchain_block, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::update_shard_client_state, masterchain_block_id, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_shard_client_state(td::Promise<BlockIdExt> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::get_shard_client_state, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::update_destroyed_validator_sessions, std::move(sessions),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::get_destroyed_validator_sessions, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::update_async_serializer_state, std::move(state), std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::get_async_serializer_state, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::start_up() {
|
||||
cell_db_ = td::actor::create_actor<CellDb>("celldb", actor_id(this), root_path_ + "/celldb/");
|
||||
block_db_ = td::actor::create_actor<BlockDb>("blockdb", actor_id(this), root_path_ + "/blockdb/");
|
||||
file_db_ = td::actor::create_actor<FileDb>("filedb", actor_id(this), root_path_ + "/files/", false);
|
||||
archive_db_ = td::actor::create_actor<FileDb>("filedbarchive", actor_id(this), root_path_ + "/archive/", true);
|
||||
lt_db_ = td::actor::create_actor<LtDb>("ltdb", actor_id(this), root_path_ + "/ltdb/");
|
||||
state_db_ = td::actor::create_actor<StateDb>("statedb", actor_id(this), root_path_ + "/state/");
|
||||
static_files_db_ = td::actor::create_actor<StaticFilesDb>("staticfilesdb", actor_id(this), root_path_ + "/static/");
|
||||
}
|
||||
|
||||
void RootDb::archive(BlockIdExt block_id, td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<BlockArchiver>("archiveblock", block_id, actor_id(this), file_db_.get(), archive_db_.get(),
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void RootDb::allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_state_gc, block_id, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::allow_block_gc(BlockIdExt block_id, td::Promise<bool> promise) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_info_gc, block_id, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> promise) {
|
||||
ref_id.visit(
|
||||
td::overloaded([&](const fileref::Empty &key) { UNREACHABLE(); },
|
||||
[&](const fileref::Block &key) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_data_gc, key.block_id,
|
||||
is_archive, std::move(promise));
|
||||
},
|
||||
[&](const fileref::ZeroState &key) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_zero_state_file_gc,
|
||||
key.block_id, std::move(promise));
|
||||
},
|
||||
[&](const fileref::PersistentState &key) {
|
||||
CHECK(is_archive);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_persistent_state_file_gc,
|
||||
key.block_id, key.masterchain_block_id, std::move(promise));
|
||||
},
|
||||
[&](const fileref::Proof &key) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_proof_gc,
|
||||
key.block_id, is_archive, std::move(promise));
|
||||
},
|
||||
[&](const fileref::ProofLink &key) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_proof_link_gc,
|
||||
key.block_id, is_archive, std::move(promise));
|
||||
},
|
||||
[&](const fileref::Signatures &key) {
|
||||
CHECK(!is_archive);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_signatures_gc,
|
||||
key.block_id, std::move(promise));
|
||||
},
|
||||
[&](const fileref::Candidate &key) {
|
||||
CHECK(!is_archive);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_candidate_gc,
|
||||
key.block_id, std::move(promise));
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
127
validator/db/rootdb.hpp
Normal file
127
validator/db/rootdb.hpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/db/KeyValueAsync.h"
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
#include "blockdb.hpp"
|
||||
#include "celldb.hpp"
|
||||
#include "filedb.hpp"
|
||||
#include "ltdb.hpp"
|
||||
#include "statedb.hpp"
|
||||
#include "staticfilesdb.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb : public Db {
|
||||
public:
|
||||
enum class Flags : td::uint32 { f_started = 1, f_ready = 2, f_switched = 4, f_archived = 8 };
|
||||
RootDb(td::actor::ActorId<ValidatorManager> validator_manager, std::string root_path)
|
||||
: validator_manager_(validator_manager), root_path_(std::move(root_path)) {
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
|
||||
void store_block_data(BlockHandle handle, td::Ref<BlockData> block, td::Promise<td::Unit> promise) override;
|
||||
void get_block_data(BlockHandle handle, td::Promise<td::Ref<BlockData>> promise) override;
|
||||
|
||||
void store_block_signatures(BlockHandle handle, td::Ref<BlockSignatureSet> data,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
void get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockSignatureSet>> promise) override;
|
||||
|
||||
void store_block_proof(BlockHandle handle, td::Ref<Proof> proof, td::Promise<td::Unit> promise) override;
|
||||
void get_block_proof(BlockHandle handle, td::Promise<td::Ref<Proof>> promise) override;
|
||||
|
||||
void store_block_proof_link(BlockHandle handle, td::Ref<ProofLink> proof, td::Promise<td::Unit> promise) override;
|
||||
void get_block_proof_link(BlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override;
|
||||
|
||||
void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
|
||||
void get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
|
||||
td::Promise<BlockCandidate> promise) override;
|
||||
|
||||
void store_block_state(BlockHandle handle, td::Ref<ShardState> state,
|
||||
td::Promise<td::Ref<ShardState>> promise) override;
|
||||
void get_block_state(BlockHandle handle, td::Promise<td::Ref<ShardState>> promise) override;
|
||||
|
||||
void store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||
void get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) override;
|
||||
void get_block_handle_external(BlockIdExt id, bool force, td::Promise<BlockHandle> promise) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManager::get_block_handle, id, force, std::move(promise));
|
||||
}
|
||||
|
||||
void store_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::BufferSlice state,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
void get_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void check_persistent_state_file_exists(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<bool> promise) override;
|
||||
void store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) override;
|
||||
void get_zero_state_file(BlockIdExt block_id, td::Promise<td::BufferSlice> promise) override;
|
||||
void check_zero_state_file_exists(BlockIdExt block_id, td::Promise<bool> promise) override;
|
||||
|
||||
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
||||
|
||||
void apply_block(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||
void get_block_by_lt(AccountIdPrefixFull account, LogicalTime lt, td::Promise<BlockIdExt> promise) override;
|
||||
void get_block_by_unix_time(AccountIdPrefixFull account, UnixTime ts, td::Promise<BlockIdExt> promise) override;
|
||||
void get_block_by_seqno(AccountIdPrefixFull account, BlockSeqno seqno, td::Promise<BlockIdExt> promise) override;
|
||||
|
||||
void update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) override;
|
||||
void get_init_masterchain_block(td::Promise<BlockIdExt> promise) override;
|
||||
|
||||
void update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) override;
|
||||
void get_gc_masterchain_block(td::Promise<BlockIdExt> promise) override;
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||
void get_shard_client_state(td::Promise<BlockIdExt> promise) override;
|
||||
|
||||
void update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
void get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) override;
|
||||
|
||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
|
||||
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
|
||||
|
||||
void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise);
|
||||
void allow_block_gc(BlockIdExt block_id, td::Promise<bool> promise);
|
||||
void allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> promise);
|
||||
|
||||
private:
|
||||
td::actor::ActorId<ValidatorManager> validator_manager_;
|
||||
|
||||
std::string root_path_;
|
||||
|
||||
td::actor::ActorOwn<CellDb> cell_db_;
|
||||
td::actor::ActorOwn<BlockDb> block_db_;
|
||||
td::actor::ActorOwn<FileDb> file_db_;
|
||||
td::actor::ActorOwn<FileDb> archive_db_;
|
||||
td::actor::ActorOwn<LtDb> lt_db_;
|
||||
td::actor::ActorOwn<StateDb> state_db_;
|
||||
td::actor::ActorOwn<StaticFilesDb> static_files_db_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
191
validator/db/statedb.cpp
Normal file
191
validator/db/statedb.cpp
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "statedb.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "td/db/RocksDb.h"
|
||||
#include "ton/ton-shard.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void StateDb::update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_initBlockId>();
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(key.as_slice(),
|
||||
create_serialize_tl_object<ton_api::db_state_initBlockId>(create_tl_block_id(block)).as_slice())
|
||||
.ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void StateDb::get_init_masterchain_block(td::Promise<BlockIdExt> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_initBlockId>();
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(key.as_slice(), value);
|
||||
R.ensure();
|
||||
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto F = fetch_tl_object<ton_api::db_state_initBlockId>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
auto obj = F.move_as_ok();
|
||||
promise.set_value(create_block_id(obj->block_));
|
||||
}
|
||||
|
||||
void StateDb::update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_gcBlockId>();
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(key.as_slice(),
|
||||
create_serialize_tl_object<ton_api::db_state_gcBlockId>(create_tl_block_id(block)).as_slice())
|
||||
.ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void StateDb::get_gc_masterchain_block(td::Promise<BlockIdExt> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_gcBlockId>();
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(key.as_slice(), value);
|
||||
R.ensure();
|
||||
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto F = fetch_tl_object<ton_api::db_state_gcBlockId>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
auto obj = F.move_as_ok();
|
||||
promise.set_value(create_block_id(obj->block_));
|
||||
}
|
||||
|
||||
void StateDb::update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_shardClient>();
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(key.as_slice(),
|
||||
create_serialize_tl_object<ton_api::db_state_shardClient>(create_tl_block_id(masterchain_block_id)))
|
||||
.ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void StateDb::get_shard_client_state(td::Promise<BlockIdExt> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_shardClient>();
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(key.as_slice(), value);
|
||||
R.ensure();
|
||||
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto F = fetch_tl_object<ton_api::db_state_shardClient>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
auto obj = F.move_as_ok();
|
||||
promise.set_value(create_block_id(obj->block_));
|
||||
}
|
||||
|
||||
void StateDb::update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
|
||||
td::Promise<td::Unit> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_destroyedSessions>();
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(key.as_slice(), create_serialize_tl_object<ton_api::db_state_destroyedSessions>(std::move(sessions)))
|
||||
.ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void StateDb::get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_destroyedSessions>();
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(key.as_slice(), value);
|
||||
R.ensure();
|
||||
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_value(std::vector<ValidatorSessionId>{});
|
||||
return;
|
||||
}
|
||||
|
||||
auto F = fetch_tl_object<ton_api::db_state_destroyedSessions>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
auto obj = F.move_as_ok();
|
||||
promise.set_value(std::move(obj->sessions_));
|
||||
}
|
||||
|
||||
void StateDb::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_asyncSerializer>();
|
||||
|
||||
auto value = create_serialize_tl_object<ton_api::db_state_asyncSerializer>(
|
||||
create_tl_block_id(state.last_block_id), create_tl_block_id(state.last_written_block_id),
|
||||
state.last_written_block_ts);
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(key.as_slice(), value.as_slice()).ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void StateDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promise) {
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_asyncSerializer>();
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(key.as_slice(), value);
|
||||
R.ensure();
|
||||
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_value(AsyncSerializerState{BlockIdExt{}, BlockIdExt{}, 0});
|
||||
return;
|
||||
}
|
||||
|
||||
auto F = fetch_tl_object<ton_api::db_state_asyncSerializer>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
auto obj = F.move_as_ok();
|
||||
promise.set_value(AsyncSerializerState{create_block_id(obj->block_), create_block_id(obj->last_),
|
||||
static_cast<UnixTime>(obj->last_ts_)});
|
||||
}
|
||||
|
||||
StateDb::StateDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
|
||||
}
|
||||
|
||||
void StateDb::start_up() {
|
||||
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
65
validator/db/statedb.hpp
Normal file
65
validator/db/statedb.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/db/KeyValueAsync.h"
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
#include "validator/interfaces/db.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb;
|
||||
|
||||
class StateDb : public td::actor::Actor {
|
||||
public:
|
||||
void update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise);
|
||||
void get_init_masterchain_block(td::Promise<BlockIdExt> promise);
|
||||
|
||||
void update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise);
|
||||
void get_gc_masterchain_block(td::Promise<BlockIdExt> promise);
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise);
|
||||
void get_shard_client_state(td::Promise<BlockIdExt> promise);
|
||||
|
||||
void update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions, td::Promise<td::Unit> promise);
|
||||
void get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise);
|
||||
|
||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise);
|
||||
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise);
|
||||
|
||||
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
|
||||
|
||||
void start_up() override;
|
||||
|
||||
private:
|
||||
using KeyType = td::Bits256;
|
||||
|
||||
std::shared_ptr<td::KeyValue> kv_;
|
||||
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
std::string db_path_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
33
validator/db/staticfilesdb.cpp
Normal file
33
validator/db/staticfilesdb.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "staticfilesdb.hpp"
|
||||
#include "files-async.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void StaticFilesDb::load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
|
||||
auto path = path_ + "/" + file_hash.to_hex();
|
||||
td::actor::create_actor<db::ReadFile>("read file", path, std::move(promise)).release();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
43
validator/db/staticfilesdb.hpp
Normal file
43
validator/db/staticfilesdb.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class RootDb;
|
||||
|
||||
class StaticFilesDb : public td::actor::Actor {
|
||||
public:
|
||||
void load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise);
|
||||
StaticFilesDb(td::actor::ActorId<RootDb> root_db, std::string path) : root_db_(root_db), path_(path) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<RootDb> root_db_;
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
233
validator/downloaders/download-state.cpp
Normal file
233
validator/downloaders/download-state.cpp
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "download-state.hpp"
|
||||
#include "validator/fabric.h"
|
||||
#include "common/checksum.h"
|
||||
#include "common/delay.h"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
DownloadShardState::DownloadShardState(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise)
|
||||
: block_id_(block_id)
|
||||
, masterchain_block_id_(masterchain_block_id)
|
||||
, priority_(priority)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void DownloadShardState::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::got_block_handle, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, block_id_, true, std::move(P));
|
||||
}
|
||||
|
||||
void DownloadShardState::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
|
||||
download_state();
|
||||
}
|
||||
|
||||
void DownloadShardState::retry() {
|
||||
download_state();
|
||||
}
|
||||
|
||||
void DownloadShardState::download_state() {
|
||||
if (handle_->id().seqno() == 0 || handle_->inited_proof() || handle_->inited_proof_link()) {
|
||||
checked_proof_link();
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
fail_handler(SelfId, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::downloaded_proof_link, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_block_proof_link_request, block_id_, priority_,
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void DownloadShardState::downloaded_proof_link(td::BufferSlice data) {
|
||||
auto pp = create_proof_link(block_id_, std::move(data));
|
||||
if (pp.is_error()) {
|
||||
fail_handler(actor_id(this), pp.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
fail_handler(SelfId, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::checked_proof_link);
|
||||
}
|
||||
});
|
||||
run_check_proof_link_query(block_id_, pp.move_as_ok(), manager_, td::Timestamp::in(60.0), std::move(P));
|
||||
}
|
||||
|
||||
void DownloadShardState::checked_proof_link() {
|
||||
if (block_id_.seqno() == 0) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::download_zero_state);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::downloaded_zero_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::try_get_static_file, block_id_.file_hash, std::move(P));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
fail_handler(SelfId, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::downloaded_shard_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
CHECK(masterchain_block_id_.is_valid());
|
||||
CHECK(masterchain_block_id_.is_masterchain());
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_persistent_state_request, block_id_,
|
||||
masterchain_block_id_, priority_, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadShardState::download_zero_state() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
fail_handler(SelfId, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::downloaded_zero_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, block_id_, priority_, std::move(P));
|
||||
}
|
||||
|
||||
void DownloadShardState::downloaded_zero_state(td::BufferSlice data) {
|
||||
if (sha256_bits256(data.as_slice()) != block_id_.file_hash) {
|
||||
fail_handler(actor_id(this), td::Status::Error(ErrorCode::protoviolation, "bad zero state: file hash mismatch"));
|
||||
return;
|
||||
}
|
||||
|
||||
data_ = std::move(data);
|
||||
auto S = create_shard_state(block_id_, data_.clone());
|
||||
S.ensure();
|
||||
state_ = S.move_as_ok();
|
||||
|
||||
CHECK(state_->root_hash() == block_id_.root_hash);
|
||||
checked_shard_state();
|
||||
}
|
||||
|
||||
void DownloadShardState::downloaded_shard_state(td::BufferSlice data) {
|
||||
auto S = create_shard_state(block_id_, data.clone());
|
||||
if (S.is_error()) {
|
||||
fail_handler(actor_id(this), S.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto state = S.move_as_ok();
|
||||
if (state->root_hash() != handle_->state()) {
|
||||
fail_handler(actor_id(this),
|
||||
td::Status::Error(ErrorCode::protoviolation, "bad persistent state: root hash mismatch"));
|
||||
return;
|
||||
}
|
||||
auto St = state->validate_deep();
|
||||
if (St.is_error()) {
|
||||
fail_handler(actor_id(this), St.move_as_error());
|
||||
return;
|
||||
}
|
||||
state_ = std::move(state);
|
||||
data_ = data.clone();
|
||||
checked_shard_state();
|
||||
}
|
||||
|
||||
void DownloadShardState::checked_shard_state() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::written_shard_state_file);
|
||||
});
|
||||
if (block_id_.seqno() == 0) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::store_zero_state_file, block_id_, std::move(data_),
|
||||
std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::store_persistent_state_file, block_id_, masterchain_block_id_,
|
||||
std::move(data_), std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadShardState::written_shard_state_file() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::written_shard_state, R.move_as_ok());
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, std::move(state_), std::move(P));
|
||||
}
|
||||
|
||||
void DownloadShardState::written_shard_state(td::Ref<ShardState> state) {
|
||||
state_ = std::move(state);
|
||||
handle_->set_unix_time(state_->get_unix_time());
|
||||
handle_->set_is_key_block(block_id_.is_masterchain());
|
||||
handle_->set_logical_time(state_->get_logical_time());
|
||||
handle_->set_applied();
|
||||
handle_->set_split(state_->before_split());
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &DownloadShardState::written_block_handle);
|
||||
});
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
}
|
||||
|
||||
void DownloadShardState::written_block_handle() {
|
||||
finish_query();
|
||||
}
|
||||
|
||||
void DownloadShardState::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(state_));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void DownloadShardState::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void DownloadShardState::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void DownloadShardState::fail_handler(td::actor::ActorId<DownloadShardState> SelfId, td::Status error) {
|
||||
LOG(WARNING) << "failed to download state : " << error;
|
||||
delay_action([=]() { td::actor::send_closure(SelfId, &DownloadShardState::retry); }, td::Timestamp::in(1.0));
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
74
validator/downloaders/download-state.hpp
Normal file
74
validator/downloaders/download-state.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class DownloadShardState : public td::actor::Actor {
|
||||
public:
|
||||
DownloadShardState(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise);
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void retry();
|
||||
void downloaded_proof_link(td::BufferSlice data);
|
||||
void checked_proof_link();
|
||||
|
||||
void download_state();
|
||||
|
||||
void download_zero_state();
|
||||
void downloaded_zero_state(td::BufferSlice data);
|
||||
|
||||
void downloaded_shard_state(td::BufferSlice data);
|
||||
|
||||
void checked_shard_state();
|
||||
void written_shard_state_file();
|
||||
void written_shard_state(td::Ref<ShardState> state);
|
||||
void written_block_handle();
|
||||
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
void abort_query(td::Status reason);
|
||||
|
||||
static void fail_handler(td::actor::ActorId<DownloadShardState> SelfId, td::Status error);
|
||||
|
||||
private:
|
||||
BlockIdExt block_id_;
|
||||
BlockIdExt masterchain_block_id_;
|
||||
|
||||
BlockHandle handle_;
|
||||
td::uint32 priority_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<ShardState>> promise_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
td::Ref<ShardState> state_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
79
validator/downloaders/wait-block-data-disk.cpp
Normal file
79
validator/downloaders/wait-block-data-disk.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "wait-block-data-disk.hpp"
|
||||
#include "fabric.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void WaitBlockDataDisk::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void WaitBlockDataDisk::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting wait block data (disk) query for block " << handle_->id() << ": " << reason;
|
||||
promise_.set_error(reason.move_as_error_prefix(PSTRING() << "failed to download (disk) " << handle_->id() << ": "));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockDataDisk::finish_query() {
|
||||
CHECK(handle_->received());
|
||||
if (promise_) {
|
||||
promise_.set_result(data_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockDataDisk::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
CHECK(handle_);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void WaitBlockDataDisk::start() {
|
||||
if (handle_->received() && (handle_->id().is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link())) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockDataDisk::abort_query, R.move_as_error_prefix("db error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockDataDisk::got_block_data_from_db, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
||||
} else {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "not in db"));
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockDataDisk::got_block_data_from_db(td::Ref<BlockData> data) {
|
||||
data_ = std::move(data);
|
||||
finish_query();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
65
validator/downloaders/wait-block-data-disk.hpp
Normal file
65
validator/downloaders/wait-block-data-disk.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/block-handle.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorManager;
|
||||
|
||||
class WaitBlockDataDisk : public td::actor::Actor {
|
||||
public:
|
||||
WaitBlockDataDisk(BlockHandle handle, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<BlockData>> promise)
|
||||
: handle_(std::move(handle)), manager_(manager), timeout_(timeout), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void update_timeout(td::Timestamp timeout) {
|
||||
if (timeout.at() > timeout_.at()) {
|
||||
timeout_ = timeout;
|
||||
alarm_timestamp() = timeout_;
|
||||
}
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void start();
|
||||
void got_block_data_from_db(td::Ref<BlockData> data);
|
||||
|
||||
private:
|
||||
BlockHandle handle_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<BlockData>> promise_;
|
||||
|
||||
td::Ref<BlockData> data_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
154
validator/downloaders/wait-block-data.cpp
Normal file
154
validator/downloaders/wait-block-data.cpp
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "wait-block-data.hpp"
|
||||
#include "fabric.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "common/delay.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void WaitBlockData::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void WaitBlockData::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
if (priority_ > 0 || (reason.code() != ErrorCode::timeout && reason.code() != ErrorCode::notready)) {
|
||||
LOG(WARNING) << "aborting wait block data query for " << handle_->id() << " priority=" << priority_ << ": "
|
||||
<< reason;
|
||||
} else {
|
||||
LOG(DEBUG) << "aborting wait block data query for " << handle_->id() << " priority=" << priority_ << ": "
|
||||
<< reason;
|
||||
}
|
||||
promise_.set_error(reason.move_as_error_prefix(PSTRING() << "failed to download " << handle_->id() << ": "));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockData::finish_query() {
|
||||
CHECK(handle_->received());
|
||||
if (promise_) {
|
||||
promise_.set_result(data_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockData::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
CHECK(handle_);
|
||||
start();
|
||||
}
|
||||
|
||||
void WaitBlockData::start() {
|
||||
if (reading_from_db_) {
|
||||
return;
|
||||
}
|
||||
if (handle_->received() &&
|
||||
(handle_->id().is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link())) {
|
||||
reading_from_db_ = true;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::abort_query, R.move_as_error_prefix("db get error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::got_block_data_from_db, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::failed_to_get_block_data_from_net,
|
||||
R.move_as_error_prefix("net error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::got_block_data_from_net, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_block_request, handle_->id(), priority_,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockData::got_block_data_from_db(td::Ref<BlockData> data) {
|
||||
data_ = std::move(data);
|
||||
finish_query();
|
||||
}
|
||||
|
||||
void WaitBlockData::failed_to_get_block_data_from_net(td::Status reason) {
|
||||
if (reason.code() == ErrorCode::notready) {
|
||||
LOG(DEBUG) << "failed to get block " << handle_->id() << " data from net: " << reason;
|
||||
} else {
|
||||
LOG(WARNING) << "failed to get block " << handle_->id() << " data from net: " << reason;
|
||||
}
|
||||
|
||||
delay_action([SelfId = actor_id(this)]() mutable { td::actor::send_closure(SelfId, &WaitBlockData::start); },
|
||||
td::Timestamp::in(0.1));
|
||||
}
|
||||
|
||||
void WaitBlockData::got_block_data_from_net(ReceivedBlock block) {
|
||||
auto X = create_block(std::move(block));
|
||||
if (X.is_error()) {
|
||||
failed_to_get_block_data_from_net(X.move_as_error_prefix("bad block from net: "));
|
||||
return;
|
||||
}
|
||||
data_ = X.move_as_ok();
|
||||
CHECK(handle_->id().is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link());
|
||||
if (!handle_->received()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::abort_query, R.move_as_error_prefix("db set error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::finish_query);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, data_, std::move(P));
|
||||
} else {
|
||||
finish_query();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockData::force_read_from_db() {
|
||||
if (reading_from_db_) {
|
||||
return;
|
||||
}
|
||||
CHECK(handle_->id().is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link());
|
||||
CHECK(handle_->received());
|
||||
reading_from_db_ = true;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::abort_query, R.move_as_error_prefix("db read error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::got_block_data_from_db, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
78
validator/downloaders/wait-block-data.hpp
Normal file
78
validator/downloaders/wait-block-data.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/block-handle.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorManager;
|
||||
|
||||
class WaitBlockData : public td::actor::Actor {
|
||||
public:
|
||||
WaitBlockData(BlockHandle handle, td::uint32 priority, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Ref<BlockData>> promise)
|
||||
: handle_(std::move(handle))
|
||||
, priority_(priority)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void update_timeout(td::Timestamp timeout, td::uint32 priority) {
|
||||
timeout_ = timeout;
|
||||
alarm_timestamp() = timeout_;
|
||||
priority_ = priority;
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void force_read_from_db();
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void start();
|
||||
void got_block_data_from_db(td::Ref<BlockData> data);
|
||||
void got_block_data_from_net(ReceivedBlock data);
|
||||
void failed_to_get_block_data_from_net(td::Status reason);
|
||||
|
||||
private:
|
||||
BlockHandle handle_;
|
||||
|
||||
td::uint32 priority_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<BlockData>> promise_;
|
||||
|
||||
td::Ref<BlockData> data_;
|
||||
|
||||
bool reading_from_db_ = false;
|
||||
|
||||
//td::PerfWarningTimer perf_timer_{"waitdata", 1.0};
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
87
validator/downloaders/wait-block-state-merge.cpp
Normal file
87
validator/downloaders/wait-block-state-merge.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "wait-block-state-merge.hpp"
|
||||
#include "wait-block-state.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void WaitBlockStateMerge::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting wait block state merge query for " << left_ << " and " << right_ << ": " << reason;
|
||||
promise_.set_error(
|
||||
reason.move_as_error_prefix(PSTRING() << "failed to download merge " << left_ << " and " << right_ << ": "));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockStateMerge::finish_query(td::Ref<ShardState> result) {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(result));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockStateMerge::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void WaitBlockStateMerge::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto P_l = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockStateMerge::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockStateMerge::got_answer, true, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, left_, priority_, timeout_,
|
||||
std::move(P_l));
|
||||
|
||||
auto P_r = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockStateMerge::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockStateMerge::got_answer, false, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, right_, priority_, timeout_,
|
||||
std::move(P_r));
|
||||
}
|
||||
|
||||
void WaitBlockStateMerge::got_answer(bool left, td::Ref<ShardState> state) {
|
||||
(left ? left_state_ : right_state_) = std::move(state);
|
||||
if (left_state_.not_null() && right_state_.not_null()) {
|
||||
auto R = left_state_->merge_with(*right_state_.get());
|
||||
if (R.is_error()) {
|
||||
abort_query(R.move_as_error_prefix("failed to merge states: "));
|
||||
} else {
|
||||
finish_query(R.move_as_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
70
validator/downloaders/wait-block-state-merge.hpp
Normal file
70
validator/downloaders/wait-block-state-merge.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorManager;
|
||||
class WaitBlockState;
|
||||
|
||||
class WaitBlockStateMerge : public td::actor::Actor {
|
||||
public:
|
||||
WaitBlockStateMerge(BlockIdExt left, BlockIdExt right, td::uint32 priority,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise)
|
||||
: left_(left)
|
||||
, right_(right)
|
||||
, priority_(priority)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query(td::Ref<ShardState> result);
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_answer(bool left, td::Ref<ShardState> state);
|
||||
|
||||
private:
|
||||
BlockIdExt left_;
|
||||
BlockIdExt right_;
|
||||
|
||||
td::uint32 priority_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<ShardState>> promise_;
|
||||
|
||||
//td::actor::ActorOwn<WaitBlockState> left_query_;
|
||||
//td::actor::ActorOwn<WaitBlockState> right_query_;
|
||||
|
||||
td::Ref<ShardState> left_state_;
|
||||
td::Ref<ShardState> right_state_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
||||
322
validator/downloaders/wait-block-state.cpp
Normal file
322
validator/downloaders/wait-block-state.cpp
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "wait-block-state.hpp"
|
||||
#include "validator/fabric.h"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "common/checksum.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void WaitBlockState::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void WaitBlockState::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
if (priority_ > 0 || (reason.code() != ErrorCode::timeout && reason.code() != ErrorCode::notready)) {
|
||||
LOG(WARNING) << "aborting wait block state query for " << handle_->id() << " priority=" << priority_ << ": "
|
||||
<< reason;
|
||||
} else {
|
||||
LOG(DEBUG) << "aborting wait block state query for " << handle_->id() << " priority=" << priority_ << ": "
|
||||
<< reason;
|
||||
}
|
||||
promise_.set_error(reason.move_as_error_prefix(PSTRING() << "failed to download state " << handle_->id() << ": "));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockState::finish_query() {
|
||||
CHECK(handle_->received_state());
|
||||
/*if (handle_->id().is_masterchain() && handle_->inited_proof()) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::new_block, handle_, prev_state_, [](td::Unit) {});
|
||||
}*/
|
||||
if (promise_) {
|
||||
promise_.set_result(prev_state_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void WaitBlockState::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
CHECK(handle_);
|
||||
start();
|
||||
}
|
||||
|
||||
void WaitBlockState::start() {
|
||||
if (reading_from_db_) {
|
||||
return;
|
||||
}
|
||||
if (handle_->received_state()) {
|
||||
reading_from_db_ = true;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("db error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_state_from_db, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, handle_, std::move(P));
|
||||
} else if (handle_->id().id.seqno == 0 && next_static_file_attempt_.is_in_past()) {
|
||||
next_static_file_attempt_ = td::Timestamp::in(60.0);
|
||||
// id.file_hash contrains correct file hash of zero state
|
||||
// => if file with this sha256 is found it is garanteed to be correct
|
||||
// => if it is not, this error is permanent
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = handle_->id()](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
if (R.error().code() == ErrorCode::notready) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::start);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("static db error: "));
|
||||
}
|
||||
} else {
|
||||
auto data = R.move_as_ok();
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_state_from_net, std::move(data));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::try_get_static_file, handle_->id().file_hash, std::move(P));
|
||||
} else if (handle_->id().id.seqno == 0) {
|
||||
// do not try to download full chain
|
||||
// download state + proof_link only
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::failed_to_get_state_from_net,
|
||||
R.move_as_error_prefix("net error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_state_from_net, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, handle_->id(), priority_,
|
||||
std::move(P));
|
||||
} else if (block_.is_null()) {
|
||||
// download block and then prev state, not in reverse only
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::failed_to_get_block_data,
|
||||
R.move_as_error_prefix("block wait error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_block_data, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, priority_, timeout_, std::move(P));
|
||||
} else if (prev_state_.is_null()) {
|
||||
CHECK(handle_->inited_proof() || handle_->inited_proof_link());
|
||||
CHECK(handle_->received());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::failed_to_get_prev_state,
|
||||
R.move_as_error_prefix("prev state wait error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_prev_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_prev_block_state, handle_, priority_, timeout_,
|
||||
std::move(P));
|
||||
} else {
|
||||
apply();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockState::failed_to_get_prev_state(td::Status reason) {
|
||||
if (reason.code() == ErrorCode::notready) {
|
||||
start();
|
||||
} else {
|
||||
abort_query(std::move(reason));
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockState::got_prev_state(td::Ref<ShardState> state) {
|
||||
prev_state_ = std::move(state);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void WaitBlockState::failed_to_get_block_data(td::Status reason) {
|
||||
if (reason.code() == ErrorCode::notready) {
|
||||
start();
|
||||
} else {
|
||||
abort_query(std::move(reason));
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockState::got_block_data(td::Ref<BlockData> data) {
|
||||
block_ = std::move(data);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void WaitBlockState::apply() {
|
||||
td::PerfWarningTimer t{"applyblocktostate", 0.1};
|
||||
auto S = prev_state_.write().apply_block(handle_->id(), block_);
|
||||
if (S.is_error()) {
|
||||
abort_query(S.move_as_error_prefix("apply error: "));
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("db set error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::written_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, prev_state_, std::move(P));
|
||||
}
|
||||
|
||||
void WaitBlockState::written_state(td::Ref<ShardState> upd_state) {
|
||||
prev_state_ = std::move(upd_state);
|
||||
finish_query();
|
||||
}
|
||||
|
||||
void WaitBlockState::got_state_from_db(td::Ref<ShardState> state) {
|
||||
prev_state_ = state;
|
||||
if (!handle_->received_state()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("db set error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::written_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, prev_state_, std::move(P));
|
||||
} else {
|
||||
finish_query();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBlockState::got_state_from_static_file(td::Ref<ShardState> state, td::BufferSlice data) {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), state = std::move(state)](td::Result<td::Unit> R) mutable {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_state_from_db, std::move(state));
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::store_zero_state_file, handle_->id(), std::move(data),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void WaitBlockState::force_read_from_db() {
|
||||
if (!handle_ || reading_from_db_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("db get error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_state_from_db, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, handle_, std::move(P));
|
||||
}
|
||||
|
||||
void WaitBlockState::got_state_from_net(td::BufferSlice data) {
|
||||
auto R = create_shard_state(handle_->id(), data.clone());
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "received bad state from net: " << R.move_as_error();
|
||||
start();
|
||||
return;
|
||||
}
|
||||
auto state = R.move_as_ok();
|
||||
|
||||
if (handle_->id().id.seqno == 0) {
|
||||
handle_->set_state_root_hash(handle_->id().root_hash);
|
||||
}
|
||||
if (state->root_hash() != handle_->state()) {
|
||||
LOG(WARNING) << "received state have bad root hash";
|
||||
start();
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_->id().id.seqno != 0) {
|
||||
auto S = state->validate_deep();
|
||||
if (S.is_error()) {
|
||||
LOG(WARNING) << "received bad state from net: " << S;
|
||||
start();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (sha256_bits256(data.as_slice()) != handle_->id().file_hash) {
|
||||
LOG(WARNING) << "received bad state from net: file hash mismatch";
|
||||
start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
handle_->set_logical_time(state->get_logical_time());
|
||||
handle_->set_unix_time(state->get_unix_time());
|
||||
handle_->set_is_key_block(handle_->id().is_masterchain() && handle_->id().id.seqno == 0);
|
||||
handle_->set_split(state->before_split());
|
||||
|
||||
prev_state_ = std::move(state);
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("db set error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::written_state_file);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::store_zero_state_file, handle_->id(), std::move(data),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void WaitBlockState::written_state_file() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::abort_query, R.move_as_error_prefix("db set error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::written_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, prev_state_, std::move(P));
|
||||
}
|
||||
|
||||
void WaitBlockState::failed_to_get_zero_state() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::failed_to_get_state_from_net,
|
||||
R.move_as_error_prefix("net error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::got_state_from_net, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, handle_->id(), priority_,
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void WaitBlockState::failed_to_get_state_from_net(td::Status reason) {
|
||||
if (reason.code() == ErrorCode::notready) {
|
||||
LOG(DEBUG) << "failed to download state for " << handle_->id() << " from net: " << reason;
|
||||
} else {
|
||||
LOG(WARNING) << "failed to download state for " << handle_->id() << " from net: " << reason;
|
||||
}
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
86
validator/downloaders/wait-block-state.hpp
Normal file
86
validator/downloaders/wait-block-state.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class WaitBlockState : public td::actor::Actor {
|
||||
public:
|
||||
WaitBlockState(BlockHandle handle, td::uint32 priority, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise)
|
||||
: handle_(std::move(handle))
|
||||
, priority_(priority)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void force_read_from_db();
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void start();
|
||||
void got_state_from_db(td::Ref<ShardState> data);
|
||||
void got_state_from_static_file(td::Ref<ShardState> state, td::BufferSlice data);
|
||||
void failed_to_get_state_from_db(td::Status reason);
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void failed_to_get_prev_state(td::Status reason);
|
||||
void got_block_data(td::Ref<BlockData> data);
|
||||
void failed_to_get_block_data(td::Status reason);
|
||||
void got_state_from_net(td::BufferSlice data);
|
||||
void failed_to_get_zero_state();
|
||||
void failed_to_get_state_from_net(td::Status reason);
|
||||
void apply();
|
||||
void written_state(td::Ref<ShardState> upd_state);
|
||||
void written_state_file();
|
||||
void update_timeout(td::Timestamp timeout, td::uint32 priority) {
|
||||
timeout_ = timeout;
|
||||
alarm_timestamp() = timeout_;
|
||||
priority_ = priority;
|
||||
}
|
||||
|
||||
private:
|
||||
BlockHandle handle_;
|
||||
|
||||
td::uint32 priority_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<ShardState>> promise_;
|
||||
|
||||
td::Ref<ShardState> prev_state_;
|
||||
td::Ref<BlockData> block_;
|
||||
|
||||
bool reading_from_db_ = false;
|
||||
td::Timestamp next_static_file_attempt_;
|
||||
|
||||
//td::PerfWarningTimer perf_timer_{"waitstate", 1.0};
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
40
validator/dummy0/CMakeLists.txt
Normal file
40
validator/dummy0/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
set(DUMMY_VALIDATOR_SOURCE
|
||||
accept-block.cpp
|
||||
fake-accept-block.cpp
|
||||
check-proof.cpp
|
||||
collate-query.cpp
|
||||
fabric.cpp
|
||||
shard.cpp
|
||||
signature-set.cpp
|
||||
top-shard-description.cpp
|
||||
validate-query.cpp
|
||||
validator-set.cpp
|
||||
|
||||
check-proof.hpp
|
||||
collate-query.hpp
|
||||
external-message.hpp
|
||||
proof.hpp
|
||||
shard.hpp
|
||||
signature-set.hpp
|
||||
top-shard-description.hpp
|
||||
validate-query.hpp
|
||||
validator-set.hpp
|
||||
)
|
||||
|
||||
add_library(dummy_validator STATIC ${DUMMY_VALIDATOR_SOURCE})
|
||||
|
||||
target_include_directories(dummy_validator PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../crypto
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(dummy_validator PRIVATE tdutils tdactor adnl tl_api dht tdfec
|
||||
overlay catchain validatorsession ton_crypto ton_block)
|
||||
332
validator/dummy0/accept-block.cpp
Normal file
332
validator/dummy0/accept-block.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "accept-block.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
#include "validator/fabric.h"
|
||||
#include "validator/invariants.hpp"
|
||||
|
||||
#include "top-shard-description.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
void AcceptBlockQuery::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting accept block " << id_ << " query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::finish_query() {
|
||||
ValidatorInvariants::check_post_accept(handle_);
|
||||
if (promise_) {
|
||||
promise_.set_value(td::Unit());
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::got_block_handle, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, id_, true, std::move(P));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
if (handle_->processed() && handle_->received() && handle_->received_state() && handle_->inited_signatures() &&
|
||||
handle_->inited_split_after() && handle_->inited_merge_before() && handle_->inited_prev() &&
|
||||
(id_.is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link())) {
|
||||
send_block_description();
|
||||
return;
|
||||
}
|
||||
if (data_.not_null() && !handle_->received()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, data_, std::move(P));
|
||||
} else {
|
||||
written_block_data();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_data() {
|
||||
if (handle_->inited_signatures()) {
|
||||
written_block_signatures();
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_signatures);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_signatures, handle_, signatures_, std::move(P));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_signatures() {
|
||||
if (prev_.size() == 2) {
|
||||
handle_->set_merge(true);
|
||||
} else {
|
||||
handle_->set_merge(false);
|
||||
}
|
||||
|
||||
for (auto &p : prev_) {
|
||||
handle_->set_prev(p);
|
||||
}
|
||||
|
||||
if (handle_->need_flush()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_info);
|
||||
}
|
||||
});
|
||||
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
} else {
|
||||
written_block_info();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_info() {
|
||||
LOG(WARNING) << "written block info";
|
||||
if (data_.not_null()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::got_prev_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
CHECK(prev_.size() <= 2);
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_prev_block_state, handle_, timeout_, std::move(P));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::failed_to_get_block_candidate);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::got_block_data, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_candidate_data_from_db, id_, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::failed_to_get_block_candidate() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::got_block_data, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, timeout_, std::move(P));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_block_data(td::Ref<BlockData> data) {
|
||||
data_ = std::move(data);
|
||||
if (handle_->received()) {
|
||||
written_block_info();
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, data_, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_prev_state(td::Ref<ShardState> state) {
|
||||
LOG(WARNING) << "got prev state";
|
||||
state_ = std::move(state);
|
||||
|
||||
state_.write().apply_block(id_, data_).ensure();
|
||||
|
||||
handle_->set_split(state_->before_split());
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_state);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, state_, std::move(P));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_state() {
|
||||
LOG(WARNING) << "written state";
|
||||
|
||||
// generate proof
|
||||
|
||||
CHECK(prev_.size() == 1);
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev;
|
||||
for (auto &p : prev_) {
|
||||
prev.emplace_back(create_tl_block_id(p));
|
||||
}
|
||||
|
||||
auto proof_link = create_tl_object<ton_api::test0_proofLink>(
|
||||
create_tl_block_id(id_), std::move(prev), Bits256_2_UInt256(state_->root_hash()), handle_->split_after());
|
||||
proof_link_ = create_proof_link(serialize_tl_object(proof_link, true)).move_as_ok();
|
||||
|
||||
if (id_.is_masterchain()) {
|
||||
auto proof = create_tl_object<ton_api::test0_proof>(
|
||||
std::move(proof_link), catchain_seqno_, validator_set_hash_,
|
||||
fetch_tl_object<ton_api::test0_blockSignatures>(signatures_->serialize(), true).move_as_ok());
|
||||
proof_ = create_proof(prev_[0], serialize_tl_object(proof, true)).move_as_ok();
|
||||
}
|
||||
|
||||
if (handle_->id().is_masterchain()) {
|
||||
CHECK(prev_.size() == 1);
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_next);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_next_block, prev_[0], id_, std::move(P));
|
||||
} else {
|
||||
written_block_next();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_next() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_proof);
|
||||
}
|
||||
});
|
||||
|
||||
if (id_.is_masterchain()) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof, handle_, proof_, std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof_link, handle_, proof_link_, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_proof() {
|
||||
if (handle_->need_flush()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::written_block_info_2);
|
||||
}
|
||||
});
|
||||
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
} else {
|
||||
written_block_info_2();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_info_2() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AcceptBlockQuery::send_block_description);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::new_block, handle_, state_, std::move(P));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::send_block_description() {
|
||||
if (!handle_->id().is_masterchain()) {
|
||||
bool after_split = prev_.size() == 1 && handle_->id().id.shard != prev_[0].id.shard;
|
||||
if (after_split) {
|
||||
CHECK(shard_parent(handle_->id().shard_full()) == prev_[0].shard_full());
|
||||
}
|
||||
bool after_merge = prev_.size() == 2;
|
||||
|
||||
auto desc = td::Ref<ShardTopBlockDescriptionImpl>{true,
|
||||
handle_->id(),
|
||||
after_split,
|
||||
after_merge,
|
||||
handle_->split_after(),
|
||||
catchain_seqno_,
|
||||
validator_set_hash_,
|
||||
signatures_->serialize()};
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_top_shard_block_description, std::move(desc));
|
||||
}
|
||||
finish_query();
|
||||
}
|
||||
|
||||
AcceptBlockQuery::AcceptBlockQuery(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
UnixTime catchain_seqno, td::uint32 validator_set_hash,
|
||||
td::Ref<BlockSignatureSet> signatures, bool send_broadcast,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise)
|
||||
: id_(id)
|
||||
, data_(std::move(data))
|
||||
, prev_(std::move(prev))
|
||||
, catchain_seqno_(catchain_seqno)
|
||||
, validator_set_hash_(validator_set_hash)
|
||||
, signatures_(std::move(signatures))
|
||||
, send_broadcast_(send_broadcast)
|
||||
, manager_(manager)
|
||||
, promise_(std::move(promise)) {
|
||||
CHECK(prev_.size() > 0);
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
94
validator/dummy0/accept-block.hpp
Normal file
94
validator/dummy0/accept-block.hpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
/*
|
||||
*
|
||||
* block data (if not given) can be obtained from:
|
||||
* db as part of collated block
|
||||
* db as block
|
||||
* net
|
||||
* must write block data, block signatures and block state
|
||||
* initialize prev, before_split, after_merge
|
||||
* for masterchain write block proof and set next for prev block
|
||||
* for masterchain run new_block callback
|
||||
*
|
||||
*/
|
||||
|
||||
class AcceptBlockQuery : public td::actor::Actor {
|
||||
public:
|
||||
AcceptBlockQuery(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev, CatchainSeqno catchain_seqno,
|
||||
td::uint32 validator_set_hash, td::Ref<BlockSignatureSet> signatures, bool send_broadcast,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void written_block_data();
|
||||
void written_block_signatures();
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void written_block_info();
|
||||
void failed_to_get_block_candidate();
|
||||
void got_block_data(td::Ref<BlockData> data);
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void written_state();
|
||||
void written_block_proof();
|
||||
void written_block_next();
|
||||
void written_block_info_2();
|
||||
void applied();
|
||||
void send_block_description();
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
td::Ref<BlockData> data_;
|
||||
std::vector<BlockIdExt> prev_;
|
||||
CatchainSeqno catchain_seqno_;
|
||||
td::uint32 validator_set_hash_;
|
||||
td::Ref<BlockSignatureSet> signatures_;
|
||||
bool send_broadcast_;
|
||||
td::Timestamp timeout_ = td::Timestamp::in(600);
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
FileHash signatures_hash_;
|
||||
BlockHandle handle_;
|
||||
td::Ref<Proof> proof_;
|
||||
td::Ref<ProofLink> proof_link_;
|
||||
|
||||
td::Ref<ShardState> state_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
62
validator/dummy0/block.hpp
Normal file
62
validator/dummy0/block.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/block.h"
|
||||
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class Block : public BlockData {
|
||||
private:
|
||||
td::BufferSlice data_;
|
||||
BlockIdExt id_;
|
||||
|
||||
public:
|
||||
td::BufferSlice data() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
FileHash file_hash() const override {
|
||||
return id_.file_hash;
|
||||
}
|
||||
BlockIdExt block_id() const override {
|
||||
return id_;
|
||||
}
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
return {};
|
||||
}
|
||||
Block *make_copy() const override {
|
||||
return new Block(id_, data_.clone());
|
||||
}
|
||||
Block(BlockIdExt id, td::BufferSlice data) : data_(std::move(data)), id_(id) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
225
validator/dummy0/check-proof.cpp
Normal file
225
validator/dummy0/check-proof.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "check-proof.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "validator/fabric.h"
|
||||
#include "validator/invariants.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
void CheckProofLink::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void CheckProofLink::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting check proof link for " << id_ << " query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void CheckProofLink::finish_query() {
|
||||
ValidatorInvariants::check_post_check_proof_link(handle_);
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "checked proof link for " << handle_->id();
|
||||
promise_.set_result(handle_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void CheckProofLink::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto F = fetch_tl_object<ton_api::test0_proofLink>(proof_->data(), true);
|
||||
if (F.is_error()) {
|
||||
abort_query(F.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
unserialized_proof_ = F.move_as_ok();
|
||||
if (create_block_id(unserialized_proof_->id_) != id_) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "proof for wrong block"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProofLink::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProofLink::got_block_handle, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, id_, true, std::move(P));
|
||||
}
|
||||
|
||||
void CheckProofLink::got_block_handle(BlockHandle handle) {
|
||||
// RUN CHECKS
|
||||
// SHOULD ONLY BE SOME MERKLE PROOFS
|
||||
// DUMMY0 DOES NOT DO IT
|
||||
|
||||
handle_ = std::move(handle);
|
||||
|
||||
std::vector<BlockIdExt> prev;
|
||||
for (auto &p : unserialized_proof_->prev_) {
|
||||
prev.push_back(create_block_id(p));
|
||||
}
|
||||
for (auto &p : prev) {
|
||||
handle_->set_prev(p);
|
||||
}
|
||||
handle_->set_merge(prev.size() == 2);
|
||||
handle_->set_split(unserialized_proof_->split_);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProofLink::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProofLink::finish_query);
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof_link, handle_, proof_, std::move(P));
|
||||
}
|
||||
void CheckProof::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void CheckProof::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting check proof for " << id_ << " query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void CheckProof::finish_query() {
|
||||
ValidatorInvariants::check_post_check_proof(handle_);
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "checked proof for " << handle_->id();
|
||||
promise_.set_result(handle_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void CheckProof::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto F = fetch_tl_object<ton_api::test0_proof>(proof_->data(), true);
|
||||
if (F.is_error()) {
|
||||
abort_query(F.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
unserialized_proof_ = F.move_as_ok();
|
||||
|
||||
auto proof_link_R = create_proof_link(serialize_tl_object(unserialized_proof_->link_, true));
|
||||
if (proof_link_R.is_error()) {
|
||||
abort_query(proof_link_R.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProof::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProof::got_block_handle, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
run_check_proof_link_query(id_, proof_link_R.move_as_ok(), manager_, timeout_, std::move(P));
|
||||
}
|
||||
|
||||
void CheckProof::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
if (handle_ && handle_->inited_proof()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProof::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProof::got_masterchain_state, td::Ref<MasterchainState>{R.move_as_ok()});
|
||||
}
|
||||
});
|
||||
CHECK(!handle_->merge_before());
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, handle_->one_prev(true), timeout_,
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void CheckProof::got_masterchain_state(td::Ref<MasterchainState> state) {
|
||||
state_ = std::move(state);
|
||||
|
||||
auto s = state_->get_validator_set(id_.shard_full());
|
||||
if (s->get_catchain_seqno() != static_cast<CatchainSeqno>(unserialized_proof_->catchain_seqno_)) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad validator set ts"));
|
||||
return;
|
||||
}
|
||||
if (s->get_validator_set_hash() != static_cast<td::uint32>(unserialized_proof_->validator_set_hash_)) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad validator set hash"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<BlockSignature> vec;
|
||||
for (auto &v : unserialized_proof_->signatures_->signatures_) {
|
||||
vec.emplace_back(BlockSignature{UInt256_2_Bits256(v->who_), std::move(v->signature_)});
|
||||
}
|
||||
|
||||
auto sigs = create_signature_set(std::move(vec));
|
||||
|
||||
auto S = s->check_signatures(id_.root_hash, id_.file_hash, sigs);
|
||||
if (S.is_error()) {
|
||||
abort_query(S.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProof::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProof::set_next);
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_next_block, handle_->one_prev(true), handle_->id(),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void CheckProof::set_next() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProof::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProof::finish_query);
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof, handle_, proof_, std::move(P));
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
99
validator/dummy0/check-proof.hpp
Normal file
99
validator/dummy0/check-proof.hpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/interfaces/block-handle.h"
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
/*
|
||||
*
|
||||
* check block proof
|
||||
* write proof
|
||||
* initialize prev, before_split, after_merge
|
||||
* initialize prev's next
|
||||
*
|
||||
*/
|
||||
|
||||
class CheckProofLink : public td::actor::Actor {
|
||||
public:
|
||||
CheckProofLink(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise)
|
||||
: id_(id), proof_(std::move(proof)), manager_(manager), timeout_(timeout), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
td::Ref<ProofLink> proof_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<BlockHandle> promise_;
|
||||
|
||||
BlockHandle handle_;
|
||||
tl_object_ptr<ton_api::test0_proofLink> unserialized_proof_;
|
||||
};
|
||||
|
||||
class CheckProof : public td::actor::Actor {
|
||||
public:
|
||||
CheckProof(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockHandle> promise)
|
||||
: id_(id), proof_(std::move(proof)), manager_(manager), timeout_(timeout), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void got_masterchain_state(td::Ref<MasterchainState> state);
|
||||
void set_next();
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
td::Ref<Proof> proof_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<BlockHandle> promise_;
|
||||
|
||||
BlockHandle handle_;
|
||||
td::Ref<MasterchainState> state_;
|
||||
tl_object_ptr<ton_api::test0_proof> unserialized_proof_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
238
validator/dummy0/collate-query.cpp
Normal file
238
validator/dummy0/collate-query.cpp
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "collate-query.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "td/utils/Random.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "shard.hpp"
|
||||
#include "validator/fabric.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
void CollateQuery::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting collate query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
void CollateQuery::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(candidate_));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void CollateQuery::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void CollateQuery::start_up() {
|
||||
//CHECK(shard_.workchain == masterchainId);
|
||||
//CHECK(shard_.shard == shardIdAll);
|
||||
LOG(WARNING) << "collate query: prev=" << prev_.size() << " ts=" << validator_set_->get_catchain_seqno();
|
||||
|
||||
alarm_timestamp() = timeout_;
|
||||
ts_ = static_cast<UnixTime>(td::Clocks::system());
|
||||
if (ts_ < min_ts_) {
|
||||
ts_ = min_ts_;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::got_prev_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
if (prev_.size() == 1) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, prev_[0], timeout_, std::move(P));
|
||||
} else {
|
||||
CHECK(prev_.size() == 2);
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_merge, prev_[0], prev_[1], timeout_,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void CollateQuery::got_prev_state(td::Ref<ShardState> recv_state) {
|
||||
prev_state_ = td::Ref<ShardStateImpl>{std::move(recv_state)};
|
||||
CHECK(prev_state_.not_null());
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<MasterchainState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::got_masterchain_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_top_masterchain_state, std::move(P));
|
||||
}
|
||||
|
||||
void CollateQuery::got_masterchain_state(td::Ref<MasterchainState> state) {
|
||||
masterchain_state_ = std::move(state);
|
||||
|
||||
if (masterchain_state_->get_block_id() < min_masterchain_block_id_) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::got_masterchain_state,
|
||||
td::Ref<MasterchainState>{R.move_as_ok()});
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, min_masterchain_block_id_, timeout_,
|
||||
std::move(P));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shard_.is_masterchain()) {
|
||||
generate();
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this)](td::Result<std::vector<td::Ref<ShardTopBlockDescription>>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::got_shard_messages, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_blocks, prev_[0], std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void CollateQuery::generate() {
|
||||
BlockSeqno seqno;
|
||||
if (prev_.size() == 1) {
|
||||
seqno = prev_[0].id.seqno + 1;
|
||||
} else {
|
||||
CHECK(prev_.size() == 2);
|
||||
seqno = std::max(prev_[0].id.seqno, prev_[1].id.seqno) + 1;
|
||||
}
|
||||
|
||||
if (shard_.is_masterchain()) {
|
||||
if (seqno <= masterchain_state_->get_seqno()) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "generating block, but newer already accepted"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto v = masterchain_state_->get_validator_set(shard_);
|
||||
if (v->get_catchain_seqno() != validator_set_->get_catchain_seqno()) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad validator set"));
|
||||
return;
|
||||
}
|
||||
CHECK(v->get_validator_set_hash() == validator_set_->get_validator_set_hash());
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev;
|
||||
for (auto& p : prev_) {
|
||||
prev.emplace_back(create_tl_block_id(p));
|
||||
}
|
||||
|
||||
auto data = td::BufferSlice{10000};
|
||||
td::Random::secure_bytes(data.as_slice());
|
||||
|
||||
auto block = create_tl_object<ton_api::test0_shardchain_block>(
|
||||
shard_.workchain, shard_.shard, seqno, std::move(prev), false, ts_, td::UInt256::zero(),
|
||||
validator_set_->get_catchain_seqno(), validator_set_->get_validator_set_hash(), std::move(data),
|
||||
create_tl_object<ton_api::test0_masterchainBlockExtra_empty>());
|
||||
|
||||
if (shard_.is_masterchain()) {
|
||||
auto m_state = td::Ref<MasterchainStateImpl>{prev_state_};
|
||||
|
||||
bool rotate = ts_ >= m_state->next_validator_rotate_at();
|
||||
|
||||
auto x = create_tl_object<ton_api::test0_masterchainBlockExtra_extra>(td::Random::fast_uint32(), rotate,
|
||||
std::move(shards_));
|
||||
block->extra_ = std::move(x);
|
||||
}
|
||||
|
||||
Bits256 x;
|
||||
x.set_zero();
|
||||
auto block_R =
|
||||
create_block(BlockIdExt{shard_.workchain, shard_.shard, seqno, x, x}, serialize_tl_object(block, true));
|
||||
if (block_R.is_error()) {
|
||||
abort_query(block_R.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto s =
|
||||
prev_state_.write().apply_block(BlockIdExt{shard_.workchain, shard_.shard, seqno, x, x}, block_R.move_as_ok());
|
||||
if (s.is_error()) {
|
||||
abort_query(std::move(s));
|
||||
return;
|
||||
}
|
||||
block->state_ = Bits256_2_UInt256(prev_state_->root_hash());
|
||||
|
||||
auto B = serialize_tl_object(block, true);
|
||||
auto file_hash = UInt256_2_Bits256(sha256_uint256(B.as_slice()));
|
||||
auto root_hash = file_hash;
|
||||
|
||||
auto collated_data = td::BufferSlice{10000};
|
||||
td::Random::secure_bytes(collated_data.as_slice());
|
||||
auto collated_data_file_hash = UInt256_2_Bits256(sha256_uint256(collated_data.as_slice()));
|
||||
|
||||
candidate_.collated_data = std::move(collated_data);
|
||||
candidate_.collated_file_hash = collated_data_file_hash;
|
||||
candidate_.data = std::move(B);
|
||||
candidate_.id = BlockIdExt{BlockId{shard_.workchain, shard_.shard, seqno}, root_hash, file_hash};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CollateQuery::finish_query);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_candidate, candidate_.id, candidate_.clone(),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void CollateQuery::got_shard_messages(std::vector<td::Ref<ShardTopBlockDescription>> shards) {
|
||||
for (auto& s : shards) {
|
||||
// TODO validate
|
||||
shards_.emplace_back(create_tl_object<ton_api::test0_masterchain_shardInfo>(
|
||||
create_tl_block_id(s->block_id()), false, s->before_split(), false, false));
|
||||
}
|
||||
generate();
|
||||
}
|
||||
|
||||
CollateQuery::CollateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise)
|
||||
: shard_(shard)
|
||||
, min_ts_(min_ts)
|
||||
, min_masterchain_block_id_{min_masterchain_block_id}
|
||||
, prev_(std::move(prev))
|
||||
, validator_set_(std::move(validator_set))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
73
validator/dummy0/collate-query.hpp
Normal file
73
validator/dummy0/collate-query.hpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
#include "shard.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class CollateQuery : public td::actor::Actor {
|
||||
public:
|
||||
CollateQuery(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise);
|
||||
|
||||
void alarm() override;
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
|
||||
void start_up() override;
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void got_masterchain_state(td::Ref<MasterchainState> state);
|
||||
void got_shard_messages(std::vector<td::Ref<ShardTopBlockDescription>> shards);
|
||||
void generate();
|
||||
void written_block_data();
|
||||
void written_block_collated_data();
|
||||
|
||||
private:
|
||||
ShardIdFull shard_;
|
||||
UnixTime min_ts_;
|
||||
BlockIdExt min_masterchain_block_id_;
|
||||
|
||||
std::vector<BlockIdExt> prev_;
|
||||
td::Ref<ValidatorSet> validator_set_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<BlockCandidate> promise_;
|
||||
|
||||
td::Ref<MasterchainState> masterchain_state_;
|
||||
td::Ref<ShardStateImpl> prev_state_;
|
||||
|
||||
BlockCandidate candidate_;
|
||||
UnixTime ts_;
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::test0_masterchain_shardInfo>> shards_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
70
validator/dummy0/external-message.hpp
Normal file
70
validator/dummy0/external-message.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/external-message.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class ExtMessageImpl : public ExtMessage {
|
||||
public:
|
||||
AccountIdPrefixFull shard() const override {
|
||||
return shard_;
|
||||
}
|
||||
td::BufferSlice serialize() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
Hash hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
|
||||
ExtMessageImpl *make_copy() const override {
|
||||
return new ExtMessageImpl{shard_, data_.clone(), hash_};
|
||||
}
|
||||
|
||||
ExtMessageImpl(AccountIdPrefixFull shard, td::BufferSlice data, Hash hash)
|
||||
: shard_(shard), data_(std::move(data)), hash_(hash) {
|
||||
}
|
||||
|
||||
ExtMessageImpl(tl_object_ptr<ton_api::test0_extMessage> data) {
|
||||
data_ = serialize_tl_object(data, true);
|
||||
hash_ = UInt256_2_Bits256(get_tl_object_sha256(data));
|
||||
shard_ = AccountIdPrefixFull{data->workchain_, static_cast<AccountIdPrefix>(data->shard_)};
|
||||
}
|
||||
|
||||
private:
|
||||
AccountIdPrefixFull shard_;
|
||||
td::BufferSlice data_;
|
||||
Hash hash_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
169
validator/dummy0/fabric.cpp
Normal file
169
validator/dummy0/fabric.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "validator/fabric.h"
|
||||
#include "block.hpp"
|
||||
#include "external-message.hpp"
|
||||
#include "proof.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include "shard.hpp"
|
||||
#include "accept-block.hpp"
|
||||
#include "fake-accept-block.hpp"
|
||||
#include "check-proof.hpp"
|
||||
#include "collate-query.hpp"
|
||||
#include "validate-query.hpp"
|
||||
#include "top-shard-description.hpp"
|
||||
|
||||
#include "validator/db/rootdb.hpp"
|
||||
#include "validator/block-handle.hpp"
|
||||
#include "validator/apply-block.hpp"
|
||||
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_) {
|
||||
return td::actor::create_actor<RootDb>("db", manager, db_root_);
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(BlockIdExt block_id, td::BufferSlice data) {
|
||||
return td::Ref<dummy0::Block>{true, block_id, std::move(data)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(ReceivedBlock data) {
|
||||
return td::Ref<dummy0::Block>{true, data.id, std::move(data.data)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<Proof>> create_proof(BlockIdExt masterchain_block_id, td::BufferSlice proof) {
|
||||
return td::Ref<dummy0::ProofImpl>{true, masterchain_block_id, std::move(proof)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ProofLink>> create_proof_link(td::BufferSlice proof) {
|
||||
return td::Ref<dummy0::ProofLinkImpl>{true, std::move(proof)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockSignatureSet>> create_signature_set(td::BufferSlice sig_set) {
|
||||
return dummy0::BlockSignatureSetImpl::fetch(std::move(sig_set));
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> create_shard_state(BlockIdExt block_id, td::BufferSlice data) {
|
||||
return dummy0::ShardStateImpl::fetch(block_id, std::move(data));
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> create_shard_state(BlockIdExt block_id, td::Ref<vm::DataCell> root_cell) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
td::Result<BlockHandle> create_block_handle(td::BufferSlice data) {
|
||||
return ton::validator::BlockHandleImpl::create(std::move(data));
|
||||
}
|
||||
|
||||
BlockHandle create_empty_block_handle(BlockIdExt id) {
|
||||
return ton::validator::BlockHandleImpl::create_empty(id);
|
||||
}
|
||||
|
||||
//td::Ref<McShardHash> create_mc_shard(ShardIdFull id, ZeroStateIdExt zero_top_block) {
|
||||
// return td::Ref<dummy0::McShardHashImpl>{true, zero_top_block};
|
||||
//}
|
||||
|
||||
td::Ref<BlockSignatureSet> create_signature_set(std::vector<BlockSignature> sig_set) {
|
||||
return td::Ref<dummy0::BlockSignatureSetImpl>{true, std::move(sig_set)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data) {
|
||||
TRY_RESULT(B, fetch_tl_object<ton_api::test0_extMessage>(std::move(data), true));
|
||||
return td::Ref<dummy0::ExtMessageImpl>{true, std::move(B)};
|
||||
}
|
||||
|
||||
void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
|
||||
bool send_broadcast, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<dummy0::AcceptBlockQuery>(
|
||||
"accept", id, std::move(data), prev, validator_set->get_catchain_seqno(), validator_set->get_validator_set_hash(),
|
||||
std::move(signatures), send_broadcast, manager, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<FakeAcceptBlockQuery>("fakeaccept", id, std::move(data), std::move(prev), 0, 0,
|
||||
td::Ref<BlockSignatureSet>{}, std::move(manager), std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<ApplyBlock>("apply", id, std::move(block), manager, timeout, std::move(promise)).release();
|
||||
}
|
||||
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise) {
|
||||
td::actor::create_actor<dummy0::CheckProof>("checkproof", id, std::move(proof), manager, timeout, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise) {
|
||||
td::actor::create_actor<dummy0::CheckProofLink>("checkprooflink", id, std::move(proof), manager, timeout,
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<ValidateCandidateResult> promise) {
|
||||
td::actor::create_actor<dummy0::ValidateQuery>(
|
||||
"validateblock", shard, min_ts, min_masterchain_block_id, std::move(prev), std::move(candidate),
|
||||
validator_set->get_catchain_seqno(), validator_set->get_validator_set_hash(), manager, timeout,
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
td::actor::create_actor<dummy0::CollateQuery>("collator", shard, min_ts, min_masterchain_block_id, std::move(prev),
|
||||
std::move(validator_set), manager, timeout, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
LOG(ERROR) << "answering";
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::testInt>(td::Random::fast_uint32()), true));
|
||||
}
|
||||
|
||||
void run_validate_shard_block_description(td::BufferSlice data, BlockHandle masterchain_block,
|
||||
td::Ref<MasterchainState> masterchain_state,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardTopBlockDescription>> promise, bool is_fake) {
|
||||
td::actor::create_actor<dummy0::ValidateShardTopBlockDescription>(
|
||||
"topshardfetch", std::move(data), std::move(masterchain_block), std::move(masterchain_state), manager, timeout,
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
227
validator/dummy0/fake-accept-block.cpp
Normal file
227
validator/dummy0/fake-accept-block.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "fake-accept-block.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
#include "fabric.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void FakeAcceptBlockQuery::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting accept block query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(td::Unit());
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::got_block_handle, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, id_, true, std::move(P));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
CHECK(!handle_->received());
|
||||
CHECK(data_.not_null());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, data_, std::move(P));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_block_data() {
|
||||
written_block_signatures();
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_block_signatures() {
|
||||
if (prev_.size() == 2) {
|
||||
handle_->set_merge(true);
|
||||
} else {
|
||||
handle_->set_merge(false);
|
||||
}
|
||||
|
||||
for (auto &p : prev_) {
|
||||
handle_->set_prev(p);
|
||||
}
|
||||
|
||||
if (handle_->need_flush()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::written_block_info);
|
||||
}
|
||||
});
|
||||
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
} else {
|
||||
written_block_info();
|
||||
}
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_block_info() {
|
||||
LOG(WARNING) << "written block info";
|
||||
CHECK(handle_->received());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::got_prev_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
CHECK(prev_.size() <= 2);
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_prev_block_state, handle_, timeout_, std::move(P));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::got_prev_state(td::Ref<ShardState> state) {
|
||||
LOG(WARNING) << "got prev state";
|
||||
state_ = std::move(state);
|
||||
|
||||
state_.write().apply_block(id_, data_).ensure();
|
||||
|
||||
handle_->set_split(state_->before_split());
|
||||
|
||||
handle_->set_state_root_hash(state_->root_hash());
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::written_state);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, state_, std::move(P));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_state() {
|
||||
LOG(WARNING) << "written state";
|
||||
if (!id_.id.is_masterchain()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
// generate proof
|
||||
|
||||
CHECK(prev_.size() == 1);
|
||||
proof_ = create_proof(prev_[0], td::BufferSlice()).move_as_ok();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::written_block_proof);
|
||||
}
|
||||
});
|
||||
//handle_->set_masterchain_block(prev_[0]);
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof, handle_, proof_, std::move(P));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_block_proof() {
|
||||
CHECK(prev_.size() <= 1);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::written_block_next);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_next_block, prev_[0], id_, std::move(P));
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_block_next() {
|
||||
if (handle_->need_flush()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::written_block_info_2);
|
||||
}
|
||||
});
|
||||
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
} else {
|
||||
written_block_info_2();
|
||||
}
|
||||
}
|
||||
|
||||
void FakeAcceptBlockQuery::written_block_info_2() {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FakeAcceptBlockQuery::finish_query);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::new_block, handle_, state_, std::move(P));
|
||||
}
|
||||
|
||||
FakeAcceptBlockQuery::FakeAcceptBlockQuery(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
UnixTime validator_set_ts, td::uint32 validator_set_hash,
|
||||
td::Ref<BlockSignatureSet> signatures,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise)
|
||||
: id_(id)
|
||||
, data_(std::move(data))
|
||||
, prev_(std::move(prev))
|
||||
, validator_set_ts_(validator_set_ts)
|
||||
, validator_set_hash_(validator_set_hash)
|
||||
, signatures_(std::move(signatures))
|
||||
, manager_(manager)
|
||||
, promise_(std::move(promise)) {
|
||||
CHECK(prev_.size() > 0);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
88
validator/dummy0/fake-accept-block.hpp
Normal file
88
validator/dummy0/fake-accept-block.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
/*
|
||||
*
|
||||
* block data (if not given) can be obtained from:
|
||||
* db as part of collated block
|
||||
* db as block
|
||||
* net
|
||||
* must write block data, block signatures and block state
|
||||
* initialize prev, before_split, after_merge
|
||||
* for masterchain write block proof and set next for prev block
|
||||
* for masterchain run new_block callback
|
||||
*
|
||||
*/
|
||||
|
||||
class FakeAcceptBlockQuery : public td::actor::Actor {
|
||||
public:
|
||||
FakeAcceptBlockQuery(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev, UnixTime validator_set_ts,
|
||||
td::uint32 validator_set_hash, td::Ref<BlockSignatureSet> signatures,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void written_block_data();
|
||||
void written_block_signatures();
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void written_block_info();
|
||||
void failed_to_get_block_candidate();
|
||||
void got_block_data(td::Ref<BlockData> data);
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void written_state();
|
||||
void written_block_proof();
|
||||
void written_block_next();
|
||||
void written_block_info_2();
|
||||
void applied();
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
td::Ref<BlockData> data_;
|
||||
std::vector<BlockIdExt> prev_;
|
||||
UnixTime validator_set_ts_;
|
||||
td::uint32 validator_set_hash_;
|
||||
td::Ref<BlockSignatureSet> signatures_;
|
||||
td::Timestamp timeout_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
FileHash signatures_hash_;
|
||||
BlockHandle handle_;
|
||||
FileHash proof_hash_;
|
||||
td::Ref<Proof> proof_;
|
||||
|
||||
td::Ref<ShardState> state_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
85
validator/dummy0/proof.hpp
Normal file
85
validator/dummy0/proof.hpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/proof.h"
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class ProofImpl : public ton::validator::Proof {
|
||||
private:
|
||||
BlockIdExt masterchain_block_id_;
|
||||
td::BufferSlice data_;
|
||||
FileHash file_hash_;
|
||||
|
||||
public:
|
||||
td::BufferSlice data() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
FileHash file_hash() const override {
|
||||
return file_hash_;
|
||||
}
|
||||
BlockIdExt masterchain_block_id() const override {
|
||||
return masterchain_block_id_;
|
||||
}
|
||||
|
||||
ProofImpl *make_copy() const override {
|
||||
return new ProofImpl(masterchain_block_id_, data_.clone(), file_hash_);
|
||||
}
|
||||
ProofImpl(BlockIdExt masterchain_block_id, td::BufferSlice data, FileHash file_hash)
|
||||
: masterchain_block_id_(masterchain_block_id), data_(std::move(data)), file_hash_(file_hash) {
|
||||
}
|
||||
ProofImpl(BlockIdExt masterchain_block_id, td::BufferSlice data)
|
||||
: masterchain_block_id_(masterchain_block_id), data_(std::move(data)) {
|
||||
file_hash_ = UInt256_2_Bits256(sha256_uint256(data_.as_slice()));
|
||||
}
|
||||
};
|
||||
|
||||
class ProofLinkImpl : public ton::validator::ProofLink {
|
||||
private:
|
||||
td::BufferSlice data_;
|
||||
FileHash file_hash_;
|
||||
|
||||
public:
|
||||
td::BufferSlice data() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
FileHash file_hash() const override {
|
||||
return file_hash_;
|
||||
}
|
||||
ProofLinkImpl *make_copy() const override {
|
||||
return new ProofLinkImpl(data_.clone(), file_hash_);
|
||||
}
|
||||
ProofLinkImpl(td::BufferSlice data, FileHash file_hash) : data_(std::move(data)), file_hash_(file_hash) {
|
||||
}
|
||||
ProofLinkImpl(td::BufferSlice data) : data_(std::move(data)) {
|
||||
file_hash_ = UInt256_2_Bits256(sha256_uint256(data_.as_slice()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
324
validator/dummy0/shard.cpp
Normal file
324
validator/dummy0/shard.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "shard.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "validator-set.hpp"
|
||||
#include "validator/interfaces/block.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
td::Ref<ton::validator::ValidatorSet> MasterchainStateImpl::calculate_validator_set(ShardIdFull shard, td::uint32 cnt,
|
||||
UnixTime ts,
|
||||
td::uint32 randseed) const {
|
||||
auto hash = ts ^ randseed;
|
||||
auto hash2 = 1000000007;
|
||||
|
||||
auto idx = hash % validators_.size();
|
||||
|
||||
std::vector<std::pair<ValidatorFullId, ValidatorWeight>> vec;
|
||||
std::map<NodeIdShort, size_t> m;
|
||||
while (cnt-- > 0) {
|
||||
auto &d = validators_[idx];
|
||||
auto id = d.short_id();
|
||||
auto it = m.find(id);
|
||||
if (it != m.end()) {
|
||||
vec[it->second].second++;
|
||||
} else {
|
||||
vec.emplace_back(d, 1);
|
||||
m[id] = vec.size() - 1;
|
||||
}
|
||||
idx = (idx + hash2) % validators_.size();
|
||||
}
|
||||
|
||||
return td::Ref<ValidatorSetImpl>{true, ts, shard.shard, std::move(vec)};
|
||||
}
|
||||
|
||||
td::Ref<ValidatorSet> MasterchainStateImpl::get_validator_set(ShardIdFull shard) const {
|
||||
//CHECK(shard.is_masterchain());
|
||||
return calculate_validator_set(shard, 200, cur_validator_ts_, cur_randseed_);
|
||||
}
|
||||
|
||||
td::Ref<ValidatorSet> MasterchainStateImpl::get_next_validator_set(ShardIdFull shard) const {
|
||||
//CHECK(shard.is_masterchain());
|
||||
return calculate_validator_set(shard, 200, cur_validator_ts_ + 1, next_randseed_);
|
||||
}
|
||||
|
||||
td::Ref<ValidatorSet> MasterchainStateImpl::get_validator_set(ShardIdFull shard, UnixTime ts) const {
|
||||
if (ts == cur_validator_ts_) {
|
||||
return get_validator_set(shard);
|
||||
} else if (ts == cur_validator_ts_ + 1) {
|
||||
return get_next_validator_set(shard);
|
||||
} else {
|
||||
return td::Ref<ValidatorSet>{};
|
||||
}
|
||||
}
|
||||
|
||||
td::Status MasterchainStateImpl::apply_block(BlockIdExt id, td::Ref<BlockData> block) {
|
||||
TRY_STATUS(ShardStateImpl::apply_block(id, block));
|
||||
TRY_RESULT(B, fetch_tl_object<ton_api::test0_shardchain_block>(block->data(), true));
|
||||
|
||||
if (B->extra_->get_id() != ton_api::test0_masterchainBlockExtra_extra::ID) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad block extra");
|
||||
}
|
||||
auto E = static_cast<const ton_api::test0_masterchainBlockExtra_extra *>(B->extra_.get());
|
||||
|
||||
if (B->prev_.size() != 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad prev size");
|
||||
}
|
||||
auto prev = create_block_id(B->prev_[0]);
|
||||
CHECK(prev.id.seqno == prev_blocks_.size());
|
||||
prev_blocks_.push_back(prev);
|
||||
|
||||
if (E->rotate_) {
|
||||
CHECK(static_cast<UnixTime>(B->ts_) >= next_validator_rotate_at_);
|
||||
next_validator_rotate_at_ = B->ts_ + 300;
|
||||
cur_validator_ts_++;
|
||||
cur_randseed_ = next_randseed_;
|
||||
next_randseed_ = E->randseed_;
|
||||
} else {
|
||||
CHECK(static_cast<UnixTime>(B->ts_) < next_validator_rotate_at_);
|
||||
}
|
||||
|
||||
for (auto &shard : E->shards_) {
|
||||
ShardDescr S{shard};
|
||||
auto shard_B = S.top_block;
|
||||
if (shard_B.id.seqno == 0) {
|
||||
for (auto &X : shards_) {
|
||||
if (X.top_block.id.workchain == shard_B.id.workchain) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad new block: duplicate zero block");
|
||||
}
|
||||
}
|
||||
shards_.emplace(std::move(S));
|
||||
} else {
|
||||
if (S.after_split) {
|
||||
if (S.top_block.id.shard == shardIdAll) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "cannot merge fullshard");
|
||||
}
|
||||
auto L = S;
|
||||
L.top_block.id.shard = shard_parent(S.top_block.id.shard);
|
||||
if (shards_.count(L) != 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown parent shard");
|
||||
}
|
||||
shards_.erase(L);
|
||||
shards_.emplace(std::move(S));
|
||||
} else if (S.after_merge) {
|
||||
auto L = S;
|
||||
L.top_block.id.shard = shard_child(S.top_block.id.shard, true);
|
||||
if (shards_.count(L) != 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown child L shard");
|
||||
}
|
||||
auto R = S;
|
||||
R.top_block.id.shard = shard_child(S.top_block.id.shard, false);
|
||||
if (shards_.count(R) != 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown child R shard");
|
||||
}
|
||||
shards_.erase(L);
|
||||
shards_.erase(R);
|
||||
shards_.emplace(std::move(S));
|
||||
} else {
|
||||
if (shards_.count(S) != 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown shard");
|
||||
}
|
||||
shards_.erase(S);
|
||||
shards_.emplace(std::move(S));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> MasterchainStateImpl::serialize() const {
|
||||
TRY_RESULT(B, ShardStateImpl::serialize());
|
||||
auto F = fetch_tl_object<ton_api::test0_shardchain_state>(std::move(B), true).move_as_ok();
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::PublicKey>> pool;
|
||||
for (auto &v : validators_) {
|
||||
pool.emplace_back(v.tl());
|
||||
}
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev;
|
||||
for (auto &p : prev_blocks_) {
|
||||
prev.emplace_back(create_tl_block_id(p));
|
||||
}
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::test0_masterchain_shardInfo>> shards;
|
||||
for (auto &shard : shards_) {
|
||||
shards.emplace_back(shard.tl());
|
||||
}
|
||||
auto obj = create_tl_object<ton_api::test0_masterchainStateExtra_extra>(
|
||||
cur_validator_ts_, cur_randseed_, next_randseed_, next_validator_rotate_at_, std::move(prev), std::move(shards),
|
||||
std::move(pool));
|
||||
F->extra_ = std::move(obj);
|
||||
return serialize_tl_object(F, true);
|
||||
}
|
||||
|
||||
td::Result<td::Ref<MasterchainState>> MasterchainStateImpl::fetch(BlockIdExt block_id, td::BufferSlice data) {
|
||||
TRY_RESULT(F, fetch_tl_object<ton_api::test0_shardchain_state>(std::move(data), true));
|
||||
|
||||
return td::Ref<MasterchainStateImpl>{true, F, block_id};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> ShardStateImpl::fetch(BlockIdExt block_id, td::BufferSlice data) {
|
||||
TRY_RESULT(F, fetch_tl_object<ton_api::test0_shardchain_state>(std::move(data), true));
|
||||
|
||||
if (block_id.id.workchain == masterchainId) {
|
||||
return td::Ref<MasterchainStateImpl>{true, F, block_id};
|
||||
} else {
|
||||
return td::Ref<ShardStateImpl>{true, F, block_id};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<td::Ref<McShardHash>> MasterchainStateImpl::get_shards() const {
|
||||
std::vector<td::Ref<McShardHash>> shards;
|
||||
for (auto &shard : shards_) {
|
||||
shards.emplace_back(shard.mc_shard());
|
||||
}
|
||||
return shards;
|
||||
}
|
||||
|
||||
MasterchainStateImpl::MasterchainStateImpl(const tl_object_ptr<ton_api::test0_shardchain_state> &state,
|
||||
BlockIdExt block_id)
|
||||
: ShardStateImpl{state, block_id} {
|
||||
CHECK(state->extra_->get_id() == ton_api::test0_masterchainStateExtra_extra::ID);
|
||||
auto E = static_cast<const ton_api::test0_masterchainStateExtra_extra *>(state->extra_.get());
|
||||
|
||||
cur_validator_ts_ = E->validator_ts_;
|
||||
cur_randseed_ = E->validator_randseed_;
|
||||
next_randseed_ = E->next_randseed_;
|
||||
next_validator_rotate_at_ = E->next_rotate_at_;
|
||||
|
||||
for (auto &v : E->pool_) {
|
||||
validators_.emplace_back(PublicKey{v});
|
||||
}
|
||||
|
||||
for (auto &p : E->prev_blocks_) {
|
||||
prev_blocks_.push_back(create_block_id(p));
|
||||
}
|
||||
|
||||
for (auto &shard : E->shards_) {
|
||||
shards_.emplace(shard);
|
||||
}
|
||||
}
|
||||
|
||||
bool MasterchainStateImpl::ancestor_is_valid(BlockIdExt id) const {
|
||||
if (id.id.seqno > get_seqno()) {
|
||||
return false;
|
||||
}
|
||||
if (id.id.seqno == get_seqno()) {
|
||||
return get_block_id() == id;
|
||||
}
|
||||
return prev_blocks_[id.id.seqno] == id;
|
||||
}
|
||||
|
||||
MasterchainStateImpl::ShardDescr::ShardDescr(const tl_object_ptr<ton_api::test0_masterchain_shardInfo> &from) {
|
||||
top_block = create_block_id(from->last_block_);
|
||||
before_merge = from->before_merge_;
|
||||
before_split = from->before_split_;
|
||||
after_merge = from->after_merge_;
|
||||
after_split = from->after_split_;
|
||||
}
|
||||
tl_object_ptr<ton_api::test0_masterchain_shardInfo> MasterchainStateImpl::ShardDescr::tl() const {
|
||||
return create_tl_object<ton_api::test0_masterchain_shardInfo>(create_tl_block_id(top_block), before_merge,
|
||||
before_split, after_merge, after_split);
|
||||
}
|
||||
td::Ref<McShardHash> MasterchainStateImpl::ShardDescr::mc_shard() const {
|
||||
return td::Ref<McShardHashImpl>{true, top_block, before_split, before_merge};
|
||||
}
|
||||
|
||||
RootHash ShardStateImpl::root_hash() const {
|
||||
auto h = sha256_uint256(serialize().move_as_ok());
|
||||
return UInt256_2_Bits256(h);
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> ShardStateImpl::serialize() const {
|
||||
auto obj =
|
||||
create_tl_object<ton_api::test0_shardchain_state>(shard_.workchain, shard_.shard, seqno_, ts_, before_split_,
|
||||
create_tl_object<ton_api::test0_masterchainStateExtra_empty>());
|
||||
return serialize_tl_object(obj, true);
|
||||
}
|
||||
|
||||
td::Status ShardStateImpl::apply_block(BlockIdExt id, td::Ref<BlockData> block) {
|
||||
TRY_RESULT(B, fetch_tl_object<ton_api::test0_shardchain_block>(block->data(), true));
|
||||
if (static_cast<BlockSeqno>(B->seqno_) != seqno_ + 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad seqno");
|
||||
}
|
||||
if (static_cast<UnixTime>(B->ts_) <= ts_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "time goes back");
|
||||
}
|
||||
if (B->workchain_ != shard_.workchain) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad workchain");
|
||||
}
|
||||
if (static_cast<ShardId>(B->shard_) != shard_.shard) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad shard");
|
||||
}
|
||||
seqno_++;
|
||||
ts_ = B->ts_;
|
||||
before_split_ = B->split_;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
ShardStateImpl::ShardStateImpl(const tl_object_ptr<ton_api::test0_shardchain_state> &state, BlockIdExt block_id) {
|
||||
blocks_id_ = {block_id};
|
||||
shard_ = ShardIdFull{state->workchain_, static_cast<ShardId>(state->shard_)};
|
||||
seqno_ = state->seqno_;
|
||||
ts_ = state->ts_;
|
||||
|
||||
before_split_ = state->split_;
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> ShardStateImpl::merge_with(const ShardState &with) const {
|
||||
auto &x = dynamic_cast<const ShardStateImpl &>(with);
|
||||
CHECK(blocks_id_.size() == 1);
|
||||
CHECK(x.blocks_id_.size() == 1);
|
||||
|
||||
return td::Ref<ShardStateImpl>{true,
|
||||
shard_parent(shard_),
|
||||
std::max(seqno_, x.seqno_),
|
||||
std::max(ts_, x.ts_),
|
||||
false,
|
||||
std::vector<BlockIdExt>{blocks_id_[0], x.blocks_id_[0]}};
|
||||
}
|
||||
|
||||
td::Result<std::pair<td::Ref<ShardState>, td::Ref<ShardState>>> ShardStateImpl::split() const {
|
||||
if (!before_split_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "split flag not raised");
|
||||
}
|
||||
CHECK(blocks_id_.size() == 1);
|
||||
|
||||
auto L = td::Ref<ShardStateImpl>{
|
||||
true, shard_child(shard_, true), seqno_, ts_, false, std::vector<BlockIdExt>{blocks_id_[0]}};
|
||||
auto R = td::Ref<ShardStateImpl>{
|
||||
true, shard_child(shard_, false), seqno_, ts_, false, std::vector<BlockIdExt>{blocks_id_[0]}};
|
||||
|
||||
return std::pair<td::Ref<ShardState>, td::Ref<ShardState>>{L, R};
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
224
validator/dummy0/shard.hpp
Normal file
224
validator/dummy0/shard.hpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class McShardHashImpl : public McShardHash {
|
||||
public:
|
||||
BlockIdExt top_block_id() const override {
|
||||
return id_;
|
||||
}
|
||||
LogicalTime start_lt() const override {
|
||||
return 0;
|
||||
}
|
||||
LogicalTime end_lt() const override {
|
||||
return 0;
|
||||
}
|
||||
UnixTime fsm_utime() const override {
|
||||
return 0;
|
||||
}
|
||||
FsmState fsm_state() const override {
|
||||
return split_ ? FsmState::fsm_split : merge_ ? FsmState::fsm_merge : FsmState::fsm_none;
|
||||
}
|
||||
bool before_split() const override {
|
||||
return split_;
|
||||
}
|
||||
bool before_merge() const override {
|
||||
return merge_;
|
||||
}
|
||||
ShardIdFull shard() const override {
|
||||
return id_.shard_full();
|
||||
}
|
||||
|
||||
McShardHashImpl(BlockIdExt id, bool split, bool merge) : id_{id}, split_(split), merge_(merge) {
|
||||
}
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
bool split_;
|
||||
bool merge_;
|
||||
};
|
||||
|
||||
class ShardStateImpl : virtual public ShardState {
|
||||
public:
|
||||
virtual ~ShardStateImpl() = default;
|
||||
static td::Result<td::Ref<ShardState>> fetch(BlockIdExt block_id, td::BufferSlice data);
|
||||
|
||||
bool disable_boc() const override {
|
||||
return true;
|
||||
}
|
||||
UnixTime get_unix_time() const override {
|
||||
return ts_;
|
||||
}
|
||||
LogicalTime get_logical_time() const override {
|
||||
return lt_;
|
||||
}
|
||||
ShardIdFull get_shard() const override {
|
||||
return shard_;
|
||||
}
|
||||
BlockSeqno get_seqno() const override {
|
||||
return seqno_;
|
||||
}
|
||||
BlockIdExt get_block_id() const override {
|
||||
CHECK(blocks_id_.size() == 1);
|
||||
return blocks_id_[0];
|
||||
}
|
||||
bool before_split() const override {
|
||||
return before_split_;
|
||||
}
|
||||
RootHash root_hash() const override;
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
td::Result<td::Ref<MessageQueue>> message_queue() const override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
td::Status apply_block(BlockIdExt id, td::Ref<BlockData> block) override;
|
||||
td::Result<td::Ref<ShardState>> merge_with(const ShardState &with) const override;
|
||||
td::Result<std::pair<td::Ref<ShardState>, td::Ref<ShardState>>> split() const override;
|
||||
td::Status validate_deep() const override {
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Result<td::BufferSlice> serialize() const override;
|
||||
ShardStateImpl *make_copy() const override {
|
||||
return new ShardStateImpl{shard_, seqno_, ts_, before_split_, blocks_id_};
|
||||
}
|
||||
|
||||
ShardStateImpl(ShardIdFull shard, BlockSeqno seqno, UnixTime ts, bool split, std::vector<BlockIdExt> block_id)
|
||||
: shard_(shard), seqno_(seqno), ts_(ts), before_split_(split), blocks_id_(block_id) {
|
||||
}
|
||||
ShardStateImpl(const tl_object_ptr<ton_api::test0_shardchain_state> &state, BlockIdExt block_id);
|
||||
|
||||
private:
|
||||
ShardIdFull shard_;
|
||||
BlockSeqno seqno_;
|
||||
UnixTime ts_;
|
||||
LogicalTime lt_ = 0;
|
||||
|
||||
bool before_split_;
|
||||
|
||||
std::vector<BlockIdExt> blocks_id_;
|
||||
};
|
||||
|
||||
class MasterchainStateImpl : public MasterchainState, public ShardStateImpl {
|
||||
public:
|
||||
struct ShardDescr {
|
||||
BlockIdExt top_block;
|
||||
bool before_split;
|
||||
bool before_merge;
|
||||
bool after_split;
|
||||
bool after_merge;
|
||||
ShardDescr(const tl_object_ptr<ton_api::test0_masterchain_shardInfo> &from);
|
||||
tl_object_ptr<ton_api::test0_masterchain_shardInfo> tl() const;
|
||||
td::Ref<McShardHash> mc_shard() const;
|
||||
bool operator<(const ShardDescr &with) const {
|
||||
return top_block.shard_full() < with.top_block.shard_full();
|
||||
}
|
||||
};
|
||||
|
||||
td::Ref<ValidatorSet> get_validator_set(ShardIdFull shard) const override;
|
||||
td::Ref<ValidatorSet> get_next_validator_set(ShardIdFull shard) const override;
|
||||
td::Ref<ValidatorSet> get_validator_set(ShardIdFull shard, UnixTime ts) const;
|
||||
bool rotated_all_shards() const override {
|
||||
return get_seqno() == 0;
|
||||
}
|
||||
UnixTime next_validator_rotate_at() const {
|
||||
return next_validator_rotate_at_;
|
||||
}
|
||||
std::vector<td::Ref<McShardHash>> get_shards() const override;
|
||||
bool ancestor_is_valid(BlockIdExt id) const override;
|
||||
|
||||
td::Status apply_block(BlockIdExt id, td::Ref<BlockData> block) override;
|
||||
td::Result<td::Ref<ShardState>> merge_with(const ShardState &with) const override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
td::Result<std::pair<td::Ref<ShardState>, td::Ref<ShardState>>> split() const override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
td::Status validate_deep() const override {
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Ref<McShardHash> get_shard_from_config(ShardIdFull shard) const override {
|
||||
auto v = get_shards();
|
||||
for (auto &x : v) {
|
||||
if (x->shard() == shard) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return td::Ref<McShardHash>{};
|
||||
}
|
||||
td::Result<td::BufferSlice> serialize() const override;
|
||||
MasterchainStateImpl *make_copy() const override {
|
||||
return new MasterchainStateImpl{get_shard(),
|
||||
get_seqno(),
|
||||
get_unix_time(),
|
||||
cur_validator_ts_,
|
||||
cur_randseed_,
|
||||
next_randseed_,
|
||||
next_validator_rotate_at_,
|
||||
validators_,
|
||||
prev_blocks_,
|
||||
shards_,
|
||||
get_block_id()};
|
||||
}
|
||||
static td::Result<td::Ref<MasterchainState>> fetch(BlockIdExt block_id, td::BufferSlice data);
|
||||
|
||||
MasterchainStateImpl(ShardIdFull shard, BlockSeqno seqno, UnixTime ts, UnixTime cur_validator_ts,
|
||||
td::uint32 cur_randseed, td::uint32 next_randseed, UnixTime next_validator_rotate_at,
|
||||
std::vector<ValidatorFullId> validators, std::vector<BlockIdExt> prev_blocks,
|
||||
std::set<ShardDescr> shards, BlockIdExt block_id)
|
||||
: ShardStateImpl{shard, seqno, ts, false, {block_id}}
|
||||
, cur_validator_ts_(cur_validator_ts)
|
||||
, cur_randseed_(cur_randseed)
|
||||
, next_randseed_(next_randseed)
|
||||
, next_validator_rotate_at_(next_validator_rotate_at)
|
||||
, validators_(std::move(validators))
|
||||
, prev_blocks_(std::move(prev_blocks))
|
||||
, shards_(std::move(shards)) {
|
||||
}
|
||||
MasterchainStateImpl(const tl_object_ptr<ton_api::test0_shardchain_state> &state, BlockIdExt block_id);
|
||||
|
||||
private:
|
||||
td::Ref<ValidatorSet> calculate_validator_set(ShardIdFull shard, td::uint32 cnt, UnixTime ts,
|
||||
td::uint32 randseed) const;
|
||||
|
||||
UnixTime cur_validator_ts_;
|
||||
td::uint32 cur_randseed_;
|
||||
td::uint32 next_randseed_;
|
||||
UnixTime next_validator_rotate_at_;
|
||||
|
||||
std::vector<ValidatorFullId> validators_;
|
||||
std::vector<BlockIdExt> prev_blocks_;
|
||||
std::set<ShardDescr> shards_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
55
validator/dummy0/signature-set.cpp
Normal file
55
validator/dummy0/signature-set.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "signature-set.hpp"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
td::BufferSlice BlockSignatureSetImpl::serialize() const {
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockSignature>> sigs;
|
||||
for (auto &s : signatures()) {
|
||||
sigs.emplace_back(
|
||||
create_tl_object<ton_api::tonNode_blockSignature>(Bits256_2_UInt256(s.node), s.signature.clone()));
|
||||
}
|
||||
auto obj = create_tl_object<ton_api::test0_blockSignatures>(std::move(sigs));
|
||||
return serialize_tl_object(obj, true);
|
||||
}
|
||||
|
||||
td::Ref<BlockSignatureSet> BlockSignatureSetImpl::fetch(td::BufferSlice data) {
|
||||
auto F = fetch_tl_object<ton_api::test0_blockSignatures>(std::move(data), true);
|
||||
auto obj = F.move_as_ok();
|
||||
|
||||
std::vector<BlockSignature> sigs;
|
||||
for (auto &s : obj->signatures_) {
|
||||
sigs.emplace_back(BlockSignature{UInt256_2_Bits256(s->who_), std::move(s->signature_)});
|
||||
}
|
||||
|
||||
return td::Ref<BlockSignatureSetImpl>{true, std::move(sigs)};
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
53
validator/dummy0/signature-set.hpp
Normal file
53
validator/dummy0/signature-set.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "validator/interfaces/signature-set.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class BlockSignatureSetImpl : public BlockSignatureSet {
|
||||
public:
|
||||
BlockSignatureSetImpl(std::vector<BlockSignature> signatures) : BlockSignatureSet{std::move(signatures)} {
|
||||
}
|
||||
|
||||
BlockSignatureSetImpl *make_copy() const override {
|
||||
std::vector<BlockSignature> vec;
|
||||
auto &sigs = signatures();
|
||||
for (auto &s : sigs) {
|
||||
vec.emplace_back(BlockSignature{s.node, s.signature.clone()});
|
||||
}
|
||||
|
||||
return new BlockSignatureSetImpl{std::move(vec)};
|
||||
}
|
||||
|
||||
td::BufferSlice serialize() const override;
|
||||
static td::Ref<BlockSignatureSet> fetch(td::BufferSlice data);
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
168
validator/dummy0/top-shard-description.cpp
Normal file
168
validator/dummy0/top-shard-description.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "top-shard-description.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "common/errorcode.h"
|
||||
#include "validator/fabric.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
bool ShardTopBlockDescriptionImpl::may_be_valid(BlockHandle last_masterchain_block_handle,
|
||||
td::Ref<MasterchainState> last_masterchain_block_state) const {
|
||||
if (after_split_ && after_merge_) {
|
||||
return false;
|
||||
}
|
||||
if (!after_split_ && !after_merge_) {
|
||||
auto s = last_masterchain_block_state->get_shard_from_config(block_id_.shard_full());
|
||||
if (s.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s->fsm_state() != McShardHash::FsmState::fsm_none) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s->top_block_id().id.seqno >= block_id_.id.seqno) {
|
||||
return false;
|
||||
}
|
||||
} else if (after_split_) {
|
||||
auto s = last_masterchain_block_state->get_shard_from_config(shard_parent(block_id_.shard_full()));
|
||||
if (s.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s->fsm_state() != McShardHash::FsmState::fsm_split) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s->top_block_id().id.seqno + 1 != block_id_.id.seqno) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
auto s1 = last_masterchain_block_state->get_shard_from_config(shard_child(block_id_.shard_full(), true));
|
||||
if (s1.is_null()) {
|
||||
return false;
|
||||
}
|
||||
auto s2 = last_masterchain_block_state->get_shard_from_config(shard_child(block_id_.shard_full(), false));
|
||||
if (s2.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s1->fsm_state() != McShardHash::FsmState::fsm_merge || s2->fsm_state() != McShardHash::FsmState::fsm_merge) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::max(s1->top_block_id().id.seqno, s2->top_block_id().id.seqno) + 1 != block_id_.id.seqno) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto val_set = last_masterchain_block_state->get_validator_set(block_id_.shard_full());
|
||||
if (val_set->get_catchain_seqno() != catchain_seqno_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
td::BufferSlice ShardTopBlockDescriptionImpl::serialize() const {
|
||||
return serialize_tl_object(create_tl_object<ton_api::test0_topShardBlockDescription>(
|
||||
create_tl_block_id(block_id_), after_split_, after_merge_, before_split_,
|
||||
catchain_seqno_, validator_set_hash_, signatures_.clone()),
|
||||
true);
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardTopBlockDescription>> ShardTopBlockDescriptionImpl::fetch(td::BufferSlice data) {
|
||||
TRY_RESULT(F, fetch_tl_object<ton_api::test0_topShardBlockDescription>(std::move(data), true));
|
||||
|
||||
return td::Ref<ShardTopBlockDescriptionImpl>{true,
|
||||
create_block_id(F->block_id_),
|
||||
F->after_split_,
|
||||
F->after_merge_,
|
||||
F->before_split_,
|
||||
F->catchain_seqno_,
|
||||
F->validator_set_hash_,
|
||||
F->signatures_.clone()};
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescription::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(ShardTopBlockDescriptionImpl::fetch(data_.clone()).move_as_ok());
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescription::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescription::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescription::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto F = fetch_tl_object<ton_api::test0_topShardBlockDescription>(data_.clone(), true);
|
||||
if (F.is_error()) {
|
||||
abort_query(F.move_as_error());
|
||||
return;
|
||||
}
|
||||
unserialized_ = F.move_as_ok();
|
||||
|
||||
auto id = create_block_id(unserialized_->block_id_);
|
||||
|
||||
auto val_set = state_->get_validator_set(id.shard_full());
|
||||
if (val_set->get_catchain_seqno() != static_cast<CatchainSeqno>(unserialized_->catchain_seqno_)) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad validator set ts"));
|
||||
return;
|
||||
}
|
||||
if (val_set->get_validator_set_hash() != static_cast<td::uint32>(unserialized_->validator_set_hash_)) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad validator set hash"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto sig_setR = create_signature_set(unserialized_->signatures_.clone());
|
||||
if (sig_setR.is_error()) {
|
||||
abort_query(sig_setR.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto S = val_set->check_signatures(id.root_hash, id.file_hash, sig_setR.move_as_ok());
|
||||
if (S.is_error()) {
|
||||
abort_query(S.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
finish_query();
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
118
validator/dummy0/top-shard-description.hpp
Normal file
118
validator/dummy0/top-shard-description.hpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/shard-block.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class ShardTopBlockDescriptionImpl : public ShardTopBlockDescription {
|
||||
public:
|
||||
ShardIdFull shard() const override {
|
||||
return block_id_.shard_full();
|
||||
}
|
||||
BlockIdExt block_id() const override {
|
||||
return block_id_;
|
||||
}
|
||||
|
||||
bool may_be_valid(BlockHandle last_masterchain_block_handle,
|
||||
td::Ref<MasterchainState> last_masterchain_block_state) const override;
|
||||
|
||||
td::BufferSlice serialize() const override;
|
||||
|
||||
bool before_split() const override {
|
||||
return before_split_;
|
||||
}
|
||||
bool after_split() const override {
|
||||
return after_split_;
|
||||
}
|
||||
bool after_merge() const override {
|
||||
return after_merge_;
|
||||
}
|
||||
|
||||
ShardTopBlockDescriptionImpl(BlockIdExt block_id, bool after_split, bool after_merge, bool before_split,
|
||||
CatchainSeqno catchain_seqno, td::uint32 validator_set_hash, td::BufferSlice signatures)
|
||||
: block_id_(block_id)
|
||||
, after_split_(after_split)
|
||||
, after_merge_(after_merge)
|
||||
, before_split_(before_split)
|
||||
, catchain_seqno_(catchain_seqno)
|
||||
, validator_set_hash_(validator_set_hash)
|
||||
, signatures_(std::move(signatures)) {
|
||||
}
|
||||
|
||||
ShardTopBlockDescriptionImpl *make_copy() const override {
|
||||
return new ShardTopBlockDescriptionImpl{block_id_, after_split_, after_merge_, before_split_,
|
||||
catchain_seqno_, validator_set_hash_, signatures_.clone()};
|
||||
}
|
||||
|
||||
static td::Result<td::Ref<ShardTopBlockDescription>> fetch(td::BufferSlice data);
|
||||
|
||||
private:
|
||||
BlockIdExt block_id_;
|
||||
bool after_split_;
|
||||
bool after_merge_;
|
||||
bool before_split_;
|
||||
|
||||
CatchainSeqno catchain_seqno_;
|
||||
td::uint32 validator_set_hash_;
|
||||
td::BufferSlice signatures_;
|
||||
};
|
||||
|
||||
class ValidateShardTopBlockDescription : public td::actor::Actor {
|
||||
public:
|
||||
ValidateShardTopBlockDescription(td::BufferSlice data, BlockHandle masterchain_handle,
|
||||
td::Ref<MasterchainState> masterchain_state,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardTopBlockDescription>> promise)
|
||||
: data_(std::move(data))
|
||||
, handle_(std::move(masterchain_handle))
|
||||
, state_(std::move(masterchain_state))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void finish_query();
|
||||
void abort_query(td::Status reason);
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
|
||||
private:
|
||||
td::BufferSlice data_;
|
||||
tl_object_ptr<ton_api::test0_topShardBlockDescription> unserialized_;
|
||||
|
||||
BlockHandle handle_;
|
||||
td::Ref<MasterchainState> state_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<ShardTopBlockDescription>> promise_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
164
validator/dummy0/validate-query.cpp
Normal file
164
validator/dummy0/validate-query.cpp
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "validate-query.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
void ValidateQuery::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void ValidateQuery::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "aborting validate block candidate query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ValidateQuery::reject_query(std::string reason, td::BufferSlice proof) {
|
||||
if (promise_) {
|
||||
LOG(WARNING) << "rejecting validate block candidate query: " << reason;
|
||||
promise_.set_value(CandidateReject{std::move(reason), std::move(proof)});
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ValidateQuery::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_result(block_ts_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ValidateQuery::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto F = fetch_tl_object<ton_api::test0_shardchain_block>(candidate_.data.clone(), true);
|
||||
if (F.is_error()) {
|
||||
abort_query(F.move_as_error());
|
||||
return;
|
||||
}
|
||||
unserialized_block_ = F.move_as_ok();
|
||||
block_ts_ = unserialized_block_->ts_;
|
||||
|
||||
if (unserialized_block_->workchain_ != shard_.workchain) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad workchain"));
|
||||
return;
|
||||
}
|
||||
if (static_cast<ShardId>(unserialized_block_->shard_) != shard_.shard) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad shard"));
|
||||
return;
|
||||
}
|
||||
|
||||
BlockSeqno max_seqno = 0;
|
||||
if (prev_.size() != unserialized_block_->prev_.size()) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "wrong prev block count"));
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < prev_.size(); i++) {
|
||||
if (prev_[i].id.seqno > max_seqno) {
|
||||
max_seqno = prev_[i].id.seqno;
|
||||
}
|
||||
auto p = create_block_id(unserialized_block_->prev_[i]);
|
||||
if (p != prev_[i]) {
|
||||
LOG(WARNING) << p << " " << prev_[i];
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "wrong prev block"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (static_cast<BlockSeqno>(unserialized_block_->seqno_) != max_seqno + 1) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "wrong block seqno"));
|
||||
return;
|
||||
}
|
||||
if (static_cast<CatchainSeqno>(unserialized_block_->catchain_seqno_) != catchain_seqno_) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "wrong validator set ts"));
|
||||
return;
|
||||
}
|
||||
if (static_cast<td::uint32>(unserialized_block_->validator_set_hash_) != validator_set_hash_) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "wrong validator set hash"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ValidateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidateQuery::got_prev_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
if (prev_.size() == 1) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, prev_[0], timeout_, std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_merge, prev_[0], prev_[1], timeout_,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateQuery::got_prev_state(td::Ref<ShardState> R) {
|
||||
if (R->get_unix_time() >= static_cast<UnixTime>(unserialized_block_->ts_)) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "too small ts"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ValidateQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidateQuery::written_candidate);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_candidate, candidate_.id, candidate_.clone(),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void ValidateQuery::written_candidate() {
|
||||
finish_query();
|
||||
}
|
||||
|
||||
ValidateQuery::ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, BlockCandidate candidate, CatchainSeqno catchain_seqno,
|
||||
td::uint32 validator_set_hash, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<ValidateCandidateResult> promise)
|
||||
: shard_(shard)
|
||||
, min_ts_(min_ts)
|
||||
, min_masterchain_block_id_(min_masterchain_block_id)
|
||||
, prev_(std::move(prev))
|
||||
, candidate_(std::move(candidate))
|
||||
, catchain_seqno_(catchain_seqno)
|
||||
, validator_set_hash_(validator_set_hash)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
68
validator/dummy0/validate-query.hpp
Normal file
68
validator/dummy0/validate-query.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class ValidateQuery : public td::actor::Actor {
|
||||
public:
|
||||
ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
BlockCandidate candidate, CatchainSeqno catchain_seqno, td::uint32 validator_set_hash,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<ValidateCandidateResult> promise);
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void reject_query(std::string reason, td::BufferSlice proof);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void got_masterchain_handle(BlockHandle masterchain_handle);
|
||||
void got_masterchain_state(td::Ref<ShardState> masterchain_state);
|
||||
void written_candidate();
|
||||
|
||||
private:
|
||||
ShardIdFull shard_;
|
||||
UnixTime min_ts_;
|
||||
BlockIdExt min_masterchain_block_id_;
|
||||
std::vector<BlockIdExt> prev_;
|
||||
BlockCandidate candidate_;
|
||||
CatchainSeqno catchain_seqno_;
|
||||
td::uint32 validator_set_hash_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<ValidateCandidateResult> promise_;
|
||||
|
||||
UnixTime block_ts_;
|
||||
tl_object_ptr<ton_api::test0_shardchain_block> unserialized_block_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
||||
116
validator/dummy0/validator-set.cpp
Normal file
116
validator/dummy0/validator-set.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "validator-set.hpp"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
bool ValidatorSetImpl::is_validator(NodeIdShort id) const {
|
||||
return ids_map_.count(id) > 0;
|
||||
}
|
||||
|
||||
td::Result<ValidatorWeight> ValidatorSetImpl::check_signatures(RootHash root_hash, FileHash file_hash,
|
||||
td::Ref<BlockSignatureSet> signatures) const {
|
||||
auto &sigs = signatures->signatures();
|
||||
|
||||
auto b = create_tl_object<ton_api::ton_blockId>(Bits256_2_UInt256(root_hash), Bits256_2_UInt256(file_hash));
|
||||
auto block = serialize_tl_object(b, true);
|
||||
|
||||
ValidatorWeight weight = 0;
|
||||
|
||||
std::set<NodeIdShort> nodes;
|
||||
for (auto &sig : sigs) {
|
||||
if (nodes.count(sig.node) == 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "duplicate node to sign");
|
||||
}
|
||||
nodes.insert(sig.node);
|
||||
|
||||
auto it = ids_map_.find(sig.node);
|
||||
if (it == ids_map_.end()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown node to sign");
|
||||
}
|
||||
|
||||
auto idx = it->second;
|
||||
TRY_STATUS(ids_[idx].encryptor->check_signature(block.as_slice(), sig.signature.as_slice()));
|
||||
weight += ids_[idx].weight;
|
||||
}
|
||||
|
||||
if (weight * 3 <= total_weight_ * 2) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too small sig weight");
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
ValidatorSetImpl::ValidatorSetImpl(CatchainSeqno cc_seqno, ShardId from,
|
||||
std::vector<std::pair<ValidatorFullId, ValidatorWeight>> nodes)
|
||||
: cc_seqno_(cc_seqno), from_(from) {
|
||||
total_weight_ = 0;
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::test0_validatorSetItem>> s_vec;
|
||||
|
||||
for (auto &n : nodes) {
|
||||
auto idx = ids_.size();
|
||||
auto id = n.first.short_id();
|
||||
s_vec.emplace_back(create_tl_object<ton_api::test0_validatorSetItem>(Bits256_2_UInt256(id), n.second));
|
||||
CHECK(ids_map_.count(id) == 0);
|
||||
total_weight_ += n.second;
|
||||
auto E = n.first.create_encryptor().move_as_ok();
|
||||
ids_.emplace_back(ValidatorSetMember{n.first, n.second, std::move(E)});
|
||||
ids_map_.emplace(id, idx);
|
||||
}
|
||||
|
||||
auto obj = create_tl_object<ton_api::test0_validatorSet>(cc_seqno_, std::move(s_vec));
|
||||
auto B = serialize_tl_object(obj, true);
|
||||
hash_ = td::crc32c(B.as_slice());
|
||||
}
|
||||
|
||||
ValidatorSetImpl *ValidatorSetImpl::make_copy() const {
|
||||
return new ValidatorSetImpl{cc_seqno_, from_, export_vector()};
|
||||
}
|
||||
|
||||
std::vector<std::pair<PublicKey, ValidatorWeight>> ValidatorSetImpl::export_tl_vector() const {
|
||||
std::vector<std::pair<PublicKey, ValidatorWeight>> vec;
|
||||
for (auto &v : ids_) {
|
||||
vec.emplace_back(v.id, v.weight);
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::vector<std::pair<ValidatorFullId, ValidatorWeight>> ValidatorSetImpl::export_vector() const {
|
||||
std::vector<std::pair<ValidatorFullId, ValidatorWeight>> vec;
|
||||
for (auto &v : ids_) {
|
||||
vec.emplace_back(v.id, v.weight);
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
74
validator/dummy0/validator-set.hpp
Normal file
74
validator/dummy0/validator-set.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/validator-set.h"
|
||||
#include "validator/interfaces/signature-set.h"
|
||||
#include "keys/encryptor.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace dummy0 {
|
||||
|
||||
class ValidatorSetImpl : public ValidatorSet {
|
||||
private:
|
||||
struct ValidatorSetMember {
|
||||
ValidatorFullId id;
|
||||
ValidatorWeight weight;
|
||||
std::unique_ptr<Encryptor> encryptor;
|
||||
};
|
||||
|
||||
public:
|
||||
bool is_validator(NodeIdShort id) const override;
|
||||
CatchainSeqno get_catchain_seqno() const override {
|
||||
return cc_seqno_;
|
||||
}
|
||||
td::uint32 get_validator_set_hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
ShardId get_validator_set_from() const override {
|
||||
return from_;
|
||||
}
|
||||
std::vector<std::pair<ValidatorFullId, ValidatorWeight>> export_vector() const override;
|
||||
std::vector<std::pair<PublicKey, ValidatorWeight>> export_tl_vector() const override;
|
||||
td::Result<ValidatorWeight> check_signatures(RootHash root_hash, FileHash file_hash,
|
||||
td::Ref<BlockSignatureSet> signatures) const override;
|
||||
|
||||
ValidatorSetImpl *make_copy() const override;
|
||||
|
||||
ValidatorSetImpl(UnixTime ts, ShardId from_, std::vector<std::pair<ValidatorFullId, ValidatorWeight>> nodes);
|
||||
|
||||
private:
|
||||
CatchainSeqno cc_seqno_;
|
||||
ShardId from_;
|
||||
td::uint32 hash_;
|
||||
ValidatorWeight total_weight_;
|
||||
std::vector<ValidatorSetMember> ids_;
|
||||
std::map<NodeIdShort, size_t> ids_map_;
|
||||
};
|
||||
|
||||
} // namespace dummy0
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
81
validator/fabric.h
Normal file
81
validator/fabric.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "interfaces/db.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_);
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(BlockIdExt block_id, td::BufferSlice data);
|
||||
td::Result<td::Ref<BlockData>> create_block(ReceivedBlock data);
|
||||
td::Result<td::Ref<Proof>> create_proof(BlockIdExt masterchain_block_id, td::BufferSlice proof);
|
||||
td::Result<td::Ref<ProofLink>> create_proof_link(BlockIdExt block_id, td::BufferSlice proof);
|
||||
td::Result<td::Ref<BlockSignatureSet>> create_signature_set(td::BufferSlice sig_set);
|
||||
td::Result<td::Ref<ShardState>> create_shard_state(BlockIdExt block_id, td::BufferSlice data);
|
||||
td::Result<td::Ref<ShardState>> create_shard_state(BlockIdExt block_id, td::Ref<vm::DataCell> root_cell);
|
||||
td::Result<BlockHandle> create_block_handle(td::BufferSlice data);
|
||||
BlockHandle create_empty_block_handle(BlockIdExt id);
|
||||
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data);
|
||||
td::Result<td::Ref<IhrMessage>> create_ihr_message(td::BufferSlice data);
|
||||
td::Result<std::vector<td::Ref<ShardTopBlockDescription>>> create_new_shard_block_descriptions(td::BufferSlice data);
|
||||
|
||||
td::Ref<BlockSignatureSet> create_signature_set(std::vector<BlockSignature> sig_set);
|
||||
|
||||
void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
|
||||
td::Ref<BlockSignatureSet> approve_signatures, bool send_broadcast,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
|
||||
void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise);
|
||||
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Unit> promise);
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise, bool skip_check_signatures = false);
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise,
|
||||
td::Ref<MasterchainState> rel_masterchain_state, bool skip_check_signatures = false);
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise,
|
||||
td::Ref<ProofLink> rel_key_block_proof, bool skip_check_signatures = false);
|
||||
void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise);
|
||||
void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
|
||||
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, PublicKeyHash local_id, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise);
|
||||
void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void run_validate_shard_block_description(td::BufferSlice data, BlockHandle masterchain_block,
|
||||
td::Ref<MasterchainState> masterchain_state,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardTopBlockDescription>> promise, bool is_fake = false);
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
649
validator/full-node-shard.cpp
Normal file
649
validator/full-node-shard.cpp
Normal file
|
|
@ -0,0 +1,649 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "full-node-shard.hpp"
|
||||
|
||||
#include "ton/ton-shard.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
#include "adnl/utils.hpp"
|
||||
#include "net/download-next-block.hpp"
|
||||
#include "net/download-block.hpp"
|
||||
#include "net/download-state.hpp"
|
||||
#include "net/download-proof.hpp"
|
||||
#include "net/get-next-key-blocks.hpp"
|
||||
|
||||
#include "common/delay.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fullnode {
|
||||
|
||||
void FullNodeShardImpl::create_overlay() {
|
||||
class Callback : public overlay::Overlays::Callback {
|
||||
public:
|
||||
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
|
||||
// just ignore
|
||||
}
|
||||
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(node_, &FullNodeShardImpl::receive_query, src, std::move(data), std::move(promise));
|
||||
}
|
||||
void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
|
||||
td::actor::send_closure(node_, &FullNodeShardImpl::receive_broadcast, src, std::move(data));
|
||||
}
|
||||
Callback(td::actor::ActorId<FullNodeShardImpl> node) : node_(node) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<FullNodeShardImpl> node_;
|
||||
};
|
||||
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::create_public_overlay, adnl_id_, overlay_id_full_.clone(),
|
||||
std::make_unique<Callback>(actor_id(this)), rules_);
|
||||
|
||||
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl_id_);
|
||||
if (cert_) {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::update_certificate, adnl_id_, overlay_id_, local_id_, cert_);
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_id_);
|
||||
adnl_id_ = adnl_id;
|
||||
create_overlay();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::try_get_next_block(td::Timestamp timeout, td::Promise<ReceivedBlock> promise) {
|
||||
if (timeout.is_in_past()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
return;
|
||||
}
|
||||
td::actor::create_actor<DownloadNextBlock>("downloadnext", adnl_id_, overlay_id_, handle_, download_next_priority(),
|
||||
timeout, validator_manager_, rldp_, overlays_, adnl_, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::got_next_block(td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
if (R.error().code() == ErrorCode::timeout) {
|
||||
get_next_block();
|
||||
return;
|
||||
}
|
||||
}
|
||||
attempt_ = 0;
|
||||
R.ensure();
|
||||
auto old_seqno = handle_->id().id.seqno;
|
||||
handle_ = R.move_as_ok();
|
||||
CHECK(handle_->id().id.seqno == old_seqno + 1);
|
||||
|
||||
if (promise_) {
|
||||
if (handle_->unix_time() > td::Clocks::system() - 300) {
|
||||
promise_.set_value(td::Unit());
|
||||
} else {
|
||||
sync_completed_at_ = td::Timestamp::in(60.0);
|
||||
}
|
||||
}
|
||||
get_next_block();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::get_next_block() {
|
||||
attempt_++;
|
||||
auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_, attempt = attempt_,
|
||||
block_id = handle_->id(), SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
|
||||
if (R.is_ok()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId](td::Result<BlockHandle> R) {
|
||||
td::actor::send_closure(SelfId, &FullNodeShardImpl::got_next_block, std::move(R));
|
||||
});
|
||||
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::validate_block, R.move_as_ok(),
|
||||
std::move(P));
|
||||
} else {
|
||||
auto S = R.move_as_error();
|
||||
if (S.code() != ErrorCode::notready && S.code() != ErrorCode::timeout) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to download next block after " << block_id << ": " << S;
|
||||
} else {
|
||||
if ((attempt % 128) == 0) {
|
||||
VLOG(FULL_NODE_INFO) << "failed to download next block after " << block_id << ": " << S;
|
||||
} else {
|
||||
VLOG(FULL_NODE_DEBUG) << "failed to download next block after " << block_id << ": " << S;
|
||||
}
|
||||
}
|
||||
delay_action([SelfId]() mutable { td::actor::send_closure(SelfId, &FullNodeShardImpl::get_next_block); },
|
||||
td::Timestamp::in(0.1));
|
||||
}
|
||||
});
|
||||
try_get_next_block(td::Timestamp::in(2.0), std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextBlockDescription &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (query.prev_block_->workchain_ != masterchainId || static_cast<ShardId>(query.prev_block_->shard_) != shardIdAll) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "next block allowed only for masterchain"));
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_blockDescriptionEmpty>();
|
||||
promise.set_value(std::move(x));
|
||||
} else {
|
||||
auto B = R.move_as_ok();
|
||||
if (!B->received() || !B->inited_proof()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_blockDescriptionEmpty>();
|
||||
promise.set_value(std::move(x));
|
||||
} else {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_blockDescription>(create_tl_block_id(B->id()));
|
||||
promise.set_value(std::move(x));
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_next_block,
|
||||
create_block_id(query.prev_block_), std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlock &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_notFound>();
|
||||
promise.set_value(std::move(x));
|
||||
} else {
|
||||
auto B = R.move_as_ok();
|
||||
if (!B->received()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_notFound>();
|
||||
promise.set_value(std::move(x));
|
||||
} else {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_prepared>();
|
||||
promise.set_value(std::move(x));
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
|
||||
create_block_id(query.block_), false, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlock &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_,
|
||||
promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block"));
|
||||
} else {
|
||||
auto B = R.move_as_ok();
|
||||
if (!B->received()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block"));
|
||||
} else {
|
||||
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_data, B, std::move(promise));
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
|
||||
create_block_id(query.block_), false, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlockProof &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (query.block_->seqno_ == 0) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot download proof for zero state"));
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([allow_partial = query.allow_partial_, promise = std::move(promise),
|
||||
validator_manager = validator_manager_](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProofEmpty>();
|
||||
promise.set_value(std::move(x));
|
||||
return;
|
||||
} else {
|
||||
auto handle = R.move_as_ok();
|
||||
if (!handle || (!handle->inited_proof() && (!allow_partial || !handle->inited_proof_link()))) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProofEmpty>();
|
||||
promise.set_value(std::move(x));
|
||||
return;
|
||||
}
|
||||
if (handle->inited_proof() && handle->id().is_masterchain()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProof>();
|
||||
promise.set_value(std::move(x));
|
||||
} else {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProofLink>();
|
||||
promise.set_value(std::move(x));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
|
||||
create_block_id(query.block_), false, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProof &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise), validator_manager = validator_manager_](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
|
||||
return;
|
||||
} else {
|
||||
auto handle = R.move_as_ok();
|
||||
if (!handle || !handle->inited_proof()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_proof, handle,
|
||||
std::move(promise));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
|
||||
create_block_id(query.block_), false, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProofLink &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise), validator_manager = validator_manager_](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
|
||||
return;
|
||||
} else {
|
||||
auto handle = R.move_as_ok();
|
||||
if (!handle || !handle->inited_proof_link()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_proof_link, handle,
|
||||
std::move(promise));
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
|
||||
create_block_id(query.block_), false, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareZeroState &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), promise = std::move(promise)](td::Result<bool> R) mutable {
|
||||
if (R.is_error() || !R.move_as_ok()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_notFoundState>();
|
||||
promise.set_value(std::move(x));
|
||||
return;
|
||||
}
|
||||
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_preparedState>();
|
||||
promise.set_value(std::move(x));
|
||||
});
|
||||
auto block_id = create_block_id(query.block_);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_zero_state_exists, block_id,
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_preparePersistentState &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), promise = std::move(promise)](td::Result<bool> R) mutable {
|
||||
if (R.is_error() || !R.move_as_ok()) {
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_notFoundState>();
|
||||
promise.set_value(std::move(x));
|
||||
return;
|
||||
}
|
||||
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_preparedState>();
|
||||
promise.set_value(std::move(x));
|
||||
});
|
||||
auto block_id = create_block_id(query.block_);
|
||||
auto masterchain_block_id = create_block_id(query.masterchain_block_);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_persistent_state_exists, block_id,
|
||||
masterchain_block_id, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto cnt = static_cast<td::uint32>(query.max_size_);
|
||||
if (cnt > 8) {
|
||||
cnt = 8;
|
||||
}
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([promise = std::move(promise), cnt](td::Result<std::vector<BlockIdExt>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "getnextkey: " << R.move_as_error();
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_keyBlocks>(
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>>{}, false, true);
|
||||
promise.set_value(std::move(x));
|
||||
return;
|
||||
}
|
||||
auto res = R.move_as_ok();
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> v;
|
||||
for (auto &b : res) {
|
||||
v.emplace_back(create_tl_block_id(b));
|
||||
}
|
||||
auto x = create_serialize_tl_object<ton_api::tonNode_keyBlocks>(std::move(v), res.size() < cnt, false);
|
||||
promise.set_value(std::move(x));
|
||||
});
|
||||
auto block_id = create_block_id(query.block_);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_next_key_blocks, block_id, cnt,
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadZeroState &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix("failed to get state from db: "));
|
||||
return;
|
||||
}
|
||||
|
||||
promise.set_value(R.move_as_ok());
|
||||
});
|
||||
auto block_id = create_block_id(query.block_);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_zero_state, block_id, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentState &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix("failed to get state from db: "));
|
||||
return;
|
||||
}
|
||||
|
||||
promise.set_value(R.move_as_ok());
|
||||
});
|
||||
auto block_id = create_block_id(query.block_);
|
||||
auto masterchain_block_id = create_block_id(query.masterchain_block_);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state, block_id,
|
||||
masterchain_block_id, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto B = fetch_tl_object<ton_api::Function>(std::move(query), true);
|
||||
if (B.is_error()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot parse tonnode query"));
|
||||
return;
|
||||
}
|
||||
ton_api::downcast_call(*B.move_as_ok().get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); });
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_ihrMessageBroadcast &query) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_ihr_message,
|
||||
std::move(query.message_->data_));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_external_message,
|
||||
std::move(query.message_->data_));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_shard_block,
|
||||
create_block_id(query.block_->block_), query.block_->cc_seqno_,
|
||||
std::move(query.block_->data_));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
|
||||
std::vector<BlockSignature> signatures;
|
||||
for (auto &sig : query.signatures_) {
|
||||
signatures.emplace_back(BlockSignature{sig->who_, std::move(sig->signature_)});
|
||||
}
|
||||
|
||||
BlockIdExt block_id = create_block_id(query.id_);
|
||||
BlockBroadcast B{block_id,
|
||||
std::move(signatures),
|
||||
static_cast<UnixTime>(query.catchain_seqno_),
|
||||
static_cast<td::uint32>(query.validator_set_hash_),
|
||||
std::move(query.data_),
|
||||
std::move(query.proof_)};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<td::Unit> R) {});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, std::move(B),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
|
||||
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
|
||||
if (B.is_error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ton_api::downcast_call(*B.move_as_ok().get(), [src, Self = this](auto &obj) { Self->process_broadcast(src, obj); });
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::send_ihr_message(td::BufferSlice data) {
|
||||
auto B = create_serialize_tl_object<ton_api::tonNode_ihrMessageBroadcast>(
|
||||
create_tl_object<ton_api::tonNode_ihrMessage>(std::move(data)));
|
||||
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, adnl_id_, overlay_id_, local_id_, 0,
|
||||
std::move(B));
|
||||
} else {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_, 0,
|
||||
std::move(B));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::send_external_message(td::BufferSlice data) {
|
||||
auto B = create_serialize_tl_object<ton_api::tonNode_externalMessageBroadcast>(
|
||||
create_tl_object<ton_api::tonNode_externalMessage>(std::move(data)));
|
||||
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, adnl_id_, overlay_id_, local_id_, 0,
|
||||
std::move(B));
|
||||
} else {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_, 0,
|
||||
std::move(B));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
|
||||
auto B = create_serialize_tl_object<ton_api::tonNode_newShardBlockBroadcast>(
|
||||
create_tl_object<ton_api::tonNode_newShardBlock>(create_tl_block_id(block_id), cc_seqno, std::move(data)));
|
||||
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, adnl_id_, overlay_id_, local_id_, 0,
|
||||
std::move(B));
|
||||
} else {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_,
|
||||
overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) {
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockSignature>> sigs;
|
||||
for (auto &sig : broadcast.signatures) {
|
||||
sigs.emplace_back(create_tl_object<ton_api::tonNode_blockSignature>(sig.node, sig.signature.clone()));
|
||||
}
|
||||
auto B = create_serialize_tl_object<ton_api::tonNode_blockBroadcast>(
|
||||
create_tl_block_id(broadcast.block_id), broadcast.catchain_seqno, broadcast.validator_set_hash, std::move(sigs),
|
||||
broadcast.proof.clone(), broadcast.data.clone());
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_,
|
||||
overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) {
|
||||
td::actor::create_actor<DownloadBlock>("downloadreq", id, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(),
|
||||
priority, timeout, validator_manager_, rldp_, overlays_, adnl_,
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::create_actor<DownloadState>("downloadstatereq", id, BlockIdExt{}, adnl_id_, overlay_id_,
|
||||
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
|
||||
overlays_, adnl_, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::create_actor<DownloadState>("downloadstatereq", id, masterchain_block_id, adnl_id_, overlay_id_,
|
||||
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
|
||||
overlays_, adnl_, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::create_actor<DownloadProof>("downloadproofreq", block_id, false, adnl_id_, overlay_id_,
|
||||
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
|
||||
overlays_, adnl_, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::create_actor<DownloadProof>("downloadproofreq", block_id, true, adnl_id_, overlay_id_,
|
||||
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
|
||||
overlays_, adnl_, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) {
|
||||
td::actor::create_actor<GetNextKeyBlocks>("next", block_id, 16, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(),
|
||||
1, timeout, validator_manager_, rldp_, overlays_, adnl_, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::set_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
CHECK(!handle_);
|
||||
handle_ = std::move(handle);
|
||||
promise_ = std::move(promise);
|
||||
get_next_block();
|
||||
|
||||
sync_completed_at_ = td::Timestamp::in(60.0);
|
||||
alarm_timestamp().relax(sync_completed_at_);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::alarm() {
|
||||
if (sync_completed_at_ && sync_completed_at_.is_in_past()) {
|
||||
if (promise_) {
|
||||
promise_.set_value(td::Unit());
|
||||
}
|
||||
sync_completed_at_ = td::Timestamp::never();
|
||||
}
|
||||
if (update_certificate_at_ && update_certificate_at_.is_in_past()) {
|
||||
if (!sign_cert_by_.is_zero()) {
|
||||
sign_new_certificate(sign_cert_by_);
|
||||
update_certificate_at_ = td::Timestamp::in(30.0);
|
||||
} else {
|
||||
update_certificate_at_ = td::Timestamp::never();
|
||||
}
|
||||
}
|
||||
alarm_timestamp().relax(sync_completed_at_);
|
||||
alarm_timestamp().relax(update_certificate_at_);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::start_up() {
|
||||
auto X =
|
||||
create_hash_tl_object<ton_api::tonNode_shardPublicOverlayId>(get_workchain(), get_shard(), zero_state_file_hash_);
|
||||
td::BufferSlice b{32};
|
||||
b.as_slice().copy_from(as_slice(X));
|
||||
overlay_id_full_ = overlay::OverlayIdFull{std::move(b)};
|
||||
overlay_id_ = overlay_id_full_.compute_short_id();
|
||||
rules_ = overlay::OverlayPrivacyRules{overlay::Overlays::max_fec_broadcast_size()};
|
||||
|
||||
create_overlay();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::sign_new_certificate(PublicKeyHash sign_by) {
|
||||
if (sign_by.is_zero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ton::overlay::Certificate cert{sign_by, static_cast<td::int32>(td::Clocks::system() + 3600),
|
||||
overlay::Overlays::max_fec_broadcast_size(), td::BufferSlice{}};
|
||||
auto to_sign = cert.to_sign(overlay_id_, local_id_);
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), cert = std::move(cert)](td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
// ignore
|
||||
VLOG(FULL_NODE_WARNING) << "failed to create certificate: failed to sign: " << R.move_as_error();
|
||||
} else {
|
||||
auto p = R.move_as_ok();
|
||||
cert.set_signature(std::move(p.first));
|
||||
cert.set_issuer(p.second);
|
||||
td::actor::send_closure(SelfId, &FullNodeShardImpl::signed_new_certificate, std::move(cert));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_add_get_public_key, sign_by, std::move(to_sign),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::signed_new_certificate(ton::overlay::Certificate cert) {
|
||||
LOG(WARNING) << "updated certificate";
|
||||
cert_ = std::make_shared<overlay::Certificate>(std::move(cert));
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::update_certificate, adnl_id_, overlay_id_, local_id_, cert_);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::update_validators(std::vector<PublicKeyHash> public_key_hashes, PublicKeyHash local_hash) {
|
||||
bool update_cert = false;
|
||||
if (!local_hash.is_zero() && local_hash != sign_cert_by_) {
|
||||
update_cert = true;
|
||||
}
|
||||
sign_cert_by_ = local_hash;
|
||||
|
||||
std::map<PublicKeyHash, td::uint32> authorized_keys;
|
||||
for (auto &key : public_key_hashes) {
|
||||
authorized_keys.emplace(key, overlay::Overlays::max_fec_broadcast_size());
|
||||
}
|
||||
|
||||
rules_ = overlay::OverlayPrivacyRules{overlay::Overlays::max_simple_broadcast_size(), std::move(authorized_keys)};
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::set_privacy_rules, adnl_id_, overlay_id_, rules_);
|
||||
|
||||
if (update_cert) {
|
||||
sign_new_certificate(sign_cert_by_);
|
||||
update_certificate_at_ = td::Timestamp::in(30.0);
|
||||
alarm_timestamp().relax(update_certificate_at_);
|
||||
}
|
||||
}
|
||||
|
||||
FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager)
|
||||
: shard_(shard)
|
||||
, local_id_(local_id)
|
||||
, adnl_id_(adnl_id)
|
||||
, zero_state_file_hash_(zero_state_file_hash)
|
||||
, keyring_(keyring)
|
||||
, adnl_(adnl)
|
||||
, rldp_(rldp)
|
||||
, overlays_(overlays)
|
||||
, validator_manager_(validator_manager) {
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<FullNodeShard> FullNodeShard::create(
|
||||
ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager) {
|
||||
return td::actor::create_actor<FullNodeShardImpl>("tonnode", shard, local_id, adnl_id, zero_state_file_hash, keyring,
|
||||
adnl, rldp, overlays, validator_manager);
|
||||
}
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
75
validator/full-node-shard.h
Normal file
75
validator/full-node-shard.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "full-node.h"
|
||||
#include "validator/interfaces/block-handle.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fullnode {
|
||||
|
||||
class FullNodeShard : public td::actor::Actor {
|
||||
public:
|
||||
virtual ~FullNodeShard() = default;
|
||||
virtual WorkchainId get_workchain() const = 0;
|
||||
virtual ShardId get_shard() const = 0;
|
||||
virtual ShardIdFull get_shard_full() const = 0;
|
||||
|
||||
virtual void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void send_ihr_message(td::BufferSlice data) = 0;
|
||||
virtual void send_external_message(td::BufferSlice data) = 0;
|
||||
virtual void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) = 0;
|
||||
virtual void send_broadcast(BlockBroadcast broadcast) = 0;
|
||||
|
||||
virtual void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) = 0;
|
||||
virtual void download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) = 0;
|
||||
|
||||
virtual void download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
||||
|
||||
virtual void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void update_validators(std::vector<PublicKeyHash> public_key_hashes, PublicKeyHash local_hash) = 0;
|
||||
|
||||
static td::actor::ActorOwn<FullNodeShard> create(ShardIdFull shard, PublicKeyHash local_id,
|
||||
adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager);
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
156
validator/full-node-shard.hpp
Normal file
156
validator/full-node-shard.hpp
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "full-node-shard.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fullnode {
|
||||
|
||||
class FullNodeShardImpl : public FullNodeShard {
|
||||
public:
|
||||
WorkchainId get_workchain() const override {
|
||||
return shard_.workchain;
|
||||
}
|
||||
ShardId get_shard() const override {
|
||||
return shard_.shard;
|
||||
}
|
||||
ShardIdFull get_shard_full() const override {
|
||||
return shard_;
|
||||
}
|
||||
|
||||
static constexpr td::uint32 download_next_priority() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void create_overlay();
|
||||
void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) override;
|
||||
|
||||
//td::Result<Block> fetch_block(td::BufferSlice data);
|
||||
void prevalidate_block(BlockIdExt block_id, td::BufferSlice data, td::BufferSlice proof,
|
||||
td::Promise<ReceivedBlock> promise);
|
||||
void try_get_next_block(td::Timestamp timestamp, td::Promise<ReceivedBlock> promise);
|
||||
void got_next_block(td::Result<BlockHandle> block);
|
||||
void get_next_block();
|
||||
|
||||
template <class T>
|
||||
void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise<td::BufferSlice> promise) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextBlockDescription &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlockProof &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProof &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProofLink &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlock &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlock &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareZeroState &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_preparePersistentState &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadZeroState &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentState &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
// void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query,
|
||||
// td::Promise<td::BufferSlice> promise);
|
||||
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_ihrMessageBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query);
|
||||
void receive_broadcast(PublicKeyHash src, td::BufferSlice query);
|
||||
|
||||
void send_ihr_message(td::BufferSlice data) override;
|
||||
void send_external_message(td::BufferSlice data) override;
|
||||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override;
|
||||
void send_broadcast(BlockBroadcast broadcast) override;
|
||||
|
||||
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) override;
|
||||
void download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) override;
|
||||
|
||||
void download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) override;
|
||||
|
||||
void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
|
||||
void update_validators(std::vector<PublicKeyHash> public_key_hashes, PublicKeyHash local_hash) override;
|
||||
void sign_new_certificate(PublicKeyHash sign_by);
|
||||
void signed_new_certificate(ton::overlay::Certificate cert);
|
||||
|
||||
FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager);
|
||||
|
||||
private:
|
||||
ShardIdFull shard_;
|
||||
BlockHandle handle_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
PublicKeyHash local_id_;
|
||||
adnl::AdnlNodeIdShort adnl_id_;
|
||||
FileHash zero_state_file_hash_;
|
||||
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
td::actor::ActorId<adnl::Adnl> adnl_;
|
||||
td::actor::ActorId<rldp::Rldp> rldp_;
|
||||
td::actor::ActorId<overlay::Overlays> overlays_;
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager_;
|
||||
|
||||
td::uint32 attempt_ = 0;
|
||||
|
||||
overlay::OverlayIdFull overlay_id_full_;
|
||||
overlay::OverlayIdShort overlay_id_;
|
||||
PublicKeyHash sign_cert_by_ = PublicKeyHash::zero();
|
||||
td::Timestamp update_certificate_at_;
|
||||
td::Timestamp sync_completed_at_;
|
||||
|
||||
std::shared_ptr<ton::overlay::Certificate> cert_;
|
||||
overlay::OverlayPrivacyRules rules_;
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
446
validator/full-node.cpp
Normal file
446
validator/full-node.cpp
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "full-node.hpp"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fullnode {
|
||||
|
||||
void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) {
|
||||
if (local_keys_.count(key)) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
|
||||
local_keys_.insert(key);
|
||||
|
||||
if (!sign_cert_by_.is_zero()) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &x : all_validators_) {
|
||||
if (x == key) {
|
||||
sign_cert_by_ = key;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void FullNodeImpl::del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) {
|
||||
if (!local_keys_.count(key)) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
local_keys_.erase(key);
|
||||
if (sign_cert_by_ != key) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
sign_cert_by_ = PublicKeyHash::zero();
|
||||
|
||||
for (auto &x : all_validators_) {
|
||||
if (local_keys_.count(x)) {
|
||||
sign_cert_by_ = x;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
|
||||
adnl_id_ = adnl_id;
|
||||
|
||||
td::MultiPromise mp;
|
||||
auto ig = mp.init_guard();
|
||||
ig.add_promise(std::move(promise));
|
||||
|
||||
for (auto &s : shards_) {
|
||||
td::actor::send_closure(s.second, &FullNodeShard::update_adnl_id, adnl_id, ig.get_promise());
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::initial_read_complete(BlockHandle top_handle) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &FullNodeImpl::sync_completed);
|
||||
});
|
||||
auto it = shards_.find(ShardIdFull{masterchainId});
|
||||
CHECK(it != shards_.end());
|
||||
td::actor::send_closure(it->second, &FullNodeShard::set_handle, top_handle, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeImpl::add_shard(ShardIdFull shard) {
|
||||
LOG(WARNING) << "add shard " << shard;
|
||||
while (true) {
|
||||
if (shards_.count(shard) == 0) {
|
||||
shards_.emplace(shard, FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, keyring_, adnl_,
|
||||
rldp_, overlays_, validator_manager_));
|
||||
if (all_validators_.size() > 0) {
|
||||
td::actor::send_closure(shards_[shard], &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (shard.shard == shardIdAll) {
|
||||
break;
|
||||
}
|
||||
shard = shard_parent(shard);
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::del_shard(ShardIdFull shard) {
|
||||
LOG(FATAL) << "deleting shards not implemented: shard=" << shard;
|
||||
shards_.erase(shard);
|
||||
}
|
||||
|
||||
void FullNodeImpl::sync_completed() {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::sync_complete, [](td::Unit) {});
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) {
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT ihr message to unknown shard";
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::send_ihr_message, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) {
|
||||
auto shard = get_shard(dst);
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT ext message to unknown shard";
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::send_external_message, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
|
||||
auto shard = get_shard(ShardIdFull{masterchainId, shardIdAll});
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT shard block info message to unknown shard";
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::send_shard_block_info, block_id, cc_seqno, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_broadcast(BlockBroadcast broadcast) {
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT broadcast to unknown shard";
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::send_broadcast, std::move(broadcast));
|
||||
}
|
||||
|
||||
void FullNodeImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) {
|
||||
auto shard = get_shard(id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download block query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_block, id, priority, timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto shard = get_shard(id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download state query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_zero_state, id, priority, timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) {
|
||||
auto shard = get_shard(id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download state diff query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_persistent_state, id, masterchain_block_id, priority, timeout,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto shard = get_shard(block_id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download proof query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_block_proof, block_id, priority, timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto shard = get_shard(block_id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download proof link query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_block_proof_link, block_id, priority, timeout,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) {
|
||||
auto shard = get_shard(block_id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download proof link query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(shard, &FullNodeShard::get_next_key_blocks, block_id, timeout, std::move(promise));
|
||||
}
|
||||
|
||||
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
|
||||
while (shards_.count(shard) == 0) {
|
||||
if (shard.shard == shardIdAll) {
|
||||
return td::actor::ActorId<FullNodeShard>{};
|
||||
}
|
||||
shard = shard_parent(shard);
|
||||
}
|
||||
return shards_[shard].get();
|
||||
}
|
||||
|
||||
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(AccountIdPrefixFull dst) {
|
||||
return get_shard(shard_prefix(dst, 60));
|
||||
}
|
||||
|
||||
void FullNodeImpl::got_key_block_proof(td::Ref<ProofLink> proof) {
|
||||
auto R = proof->get_key_block_config();
|
||||
R.ensure();
|
||||
auto config = R.move_as_ok();
|
||||
|
||||
PublicKeyHash l = PublicKeyHash::zero();
|
||||
std::vector<PublicKeyHash> keys;
|
||||
for (td::int32 i = -1; i <= 1; i++) {
|
||||
auto r = config->get_total_validator_set(i < 0 ? i : 1 - i);
|
||||
if (r.not_null()) {
|
||||
auto vec = r->export_vector();
|
||||
for (auto &el : vec) {
|
||||
auto key = ValidatorFullId{el.key}.compute_short_id();
|
||||
keys.push_back(key);
|
||||
if (local_keys_.count(key)) {
|
||||
l = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keys == all_validators_) {
|
||||
return;
|
||||
}
|
||||
|
||||
all_validators_ = keys;
|
||||
sign_cert_by_ = l;
|
||||
CHECK(all_validators_.size() > 0);
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::got_zero_block_state(td::Ref<ShardState> state) {
|
||||
auto m = td::Ref<MasterchainState>{std::move(state)};
|
||||
|
||||
PublicKeyHash l = PublicKeyHash::zero();
|
||||
std::vector<PublicKeyHash> keys;
|
||||
for (td::int32 i = -1; i <= 1; i++) {
|
||||
auto r = m->get_total_validator_set(i < 0 ? i : 1 - i);
|
||||
if (r.not_null()) {
|
||||
auto vec = r->export_vector();
|
||||
for (auto &el : vec) {
|
||||
auto key = ValidatorFullId{el.key}.compute_short_id();
|
||||
keys.push_back(key);
|
||||
if (local_keys_.count(key)) {
|
||||
l = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keys == all_validators_) {
|
||||
return;
|
||||
}
|
||||
|
||||
all_validators_ = keys;
|
||||
sign_cert_by_ = l;
|
||||
CHECK(all_validators_.size() > 0);
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::new_key_block(BlockHandle handle) {
|
||||
if (handle->id().seqno() == 0) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to get zero state: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FullNodeImpl::got_zero_block_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_shard_state_from_db, handle,
|
||||
std::move(P));
|
||||
} else {
|
||||
CHECK(handle->is_key_block());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ProofLink>> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to get key block proof: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FullNodeImpl::got_key_block_proof, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_proof_link_from_db, handle,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::start_up() {
|
||||
if (local_id_.is_zero()) {
|
||||
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
||||
local_id_ = pk.compute_short_id();
|
||||
|
||||
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
|
||||
}
|
||||
class Callback : public ValidatorManagerInterface::Callback {
|
||||
public:
|
||||
void initial_read_complete(BlockHandle handle) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::initial_read_complete, handle);
|
||||
}
|
||||
void add_shard(ShardIdFull shard) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::add_shard, shard);
|
||||
}
|
||||
void del_shard(ShardIdFull shard) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::del_shard, shard);
|
||||
}
|
||||
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_ihr_message, dst, std::move(data));
|
||||
}
|
||||
void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_ext_message, dst, std::move(data));
|
||||
}
|
||||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_shard_block_info, block_id, cc_seqno, std::move(data));
|
||||
}
|
||||
void send_broadcast(BlockBroadcast broadcast) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_broadcast, std::move(broadcast));
|
||||
}
|
||||
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_block, id, priority, timeout, std::move(promise));
|
||||
}
|
||||
void download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_zero_state, id, priority, timeout, std::move(promise));
|
||||
}
|
||||
void download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_persistent_state, id, masterchain_block_id, priority,
|
||||
timeout, std::move(promise));
|
||||
}
|
||||
void download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_block_proof, block_id, priority, timeout,
|
||||
std::move(promise));
|
||||
}
|
||||
void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_block_proof_link, block_id, priority, timeout,
|
||||
std::move(promise));
|
||||
}
|
||||
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::get_next_key_blocks, block_id, timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void new_key_block(BlockHandle handle) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::new_key_block, std::move(handle));
|
||||
}
|
||||
|
||||
Callback(td::actor::ActorId<FullNodeImpl> id) : id_(id) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<FullNodeImpl> id_;
|
||||
};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([](td::Unit R) {});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::install_callback,
|
||||
std::make_unique<Callback>(actor_id(this)), std::move(P));
|
||||
}
|
||||
|
||||
FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager, std::string db_root)
|
||||
: local_id_(local_id)
|
||||
, adnl_id_(adnl_id)
|
||||
, zero_state_file_hash_(zero_state_file_hash)
|
||||
, keyring_(keyring)
|
||||
, adnl_(adnl)
|
||||
, rldp_(rldp)
|
||||
, dht_(dht)
|
||||
, overlays_(overlays)
|
||||
, validator_manager_(validator_manager)
|
||||
, db_root_(db_root) {
|
||||
add_shard(ShardIdFull{masterchainId});
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<FullNode> FullNode::create(ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
std::string db_root) {
|
||||
return td::actor::create_actor<FullNodeImpl>("fullnode", local_id, adnl_id, zero_state_file_hash, keyring, adnl, rldp,
|
||||
dht, overlays, validator_manager, db_root);
|
||||
}
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
81
validator/full-node.h
Normal file
81
validator/full-node.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "adnl/adnl.h"
|
||||
#include "rldp/rldp.h"
|
||||
#include "dht/dht.h"
|
||||
#include "overlay/overlays.h"
|
||||
#include "validator/validator.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fullnode {
|
||||
|
||||
constexpr int VERBOSITY_NAME(FULL_NODE_WARNING) = verbosity_WARNING;
|
||||
constexpr int VERBOSITY_NAME(FULL_NODE_NOTICE) = verbosity_INFO;
|
||||
constexpr int VERBOSITY_NAME(FULL_NODE_INFO) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(FULL_NODE_DEBUG) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(FULL_NODE_EXTRA_DEBUG) = verbosity_DEBUG + 1;
|
||||
|
||||
class FullNode : public td::actor::Actor {
|
||||
public:
|
||||
virtual ~FullNode() = default;
|
||||
|
||||
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht) = 0;
|
||||
|
||||
virtual void add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
static constexpr td::uint32 max_block_size() {
|
||||
return 4 << 20;
|
||||
}
|
||||
static constexpr td::uint32 max_proof_size() {
|
||||
return 4 << 20;
|
||||
}
|
||||
static constexpr td::uint64 max_state_size() {
|
||||
return 4ull << 30;
|
||||
}
|
||||
|
||||
static td::actor::ActorOwn<FullNode> create(ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
std::string db_root);
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
109
validator/full-node.hpp
Normal file
109
validator/full-node.hpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "full-node.h"
|
||||
#include "full-node-shard.h"
|
||||
//#include "ton-node-slave.h"
|
||||
#include "interfaces/proof.h"
|
||||
#include "interfaces/shard.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
namespace fullnode {
|
||||
|
||||
class FullNodeImpl : public FullNode {
|
||||
public:
|
||||
void update_dht_node(td::actor::ActorId<dht::Dht> dht) override {
|
||||
dht_ = dht;
|
||||
}
|
||||
|
||||
void add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) override;
|
||||
void del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void add_shard(ShardIdFull shard);
|
||||
void del_shard(ShardIdFull shard);
|
||||
|
||||
void sync_completed();
|
||||
|
||||
void initial_read_complete(BlockHandle top_block);
|
||||
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data);
|
||||
void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data);
|
||||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqnp, td::BufferSlice data);
|
||||
void send_broadcast(BlockBroadcast broadcast);
|
||||
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout, td::Promise<ReceivedBlock> promise);
|
||||
void download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::BufferSlice> promise);
|
||||
void download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout, td::Promise<std::vector<BlockIdExt>> promise);
|
||||
|
||||
void got_key_block_proof(td::Ref<ProofLink> proof);
|
||||
void got_zero_block_state(td::Ref<ShardState> state);
|
||||
void new_key_block(BlockHandle handle);
|
||||
|
||||
void start_up() override;
|
||||
|
||||
FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager, std::string db_root);
|
||||
|
||||
private:
|
||||
PublicKeyHash local_id_;
|
||||
adnl::AdnlNodeIdShort adnl_id_;
|
||||
FileHash zero_state_file_hash_;
|
||||
|
||||
td::actor::ActorId<FullNodeShard> get_shard(AccountIdPrefixFull dst);
|
||||
td::actor::ActorId<FullNodeShard> get_shard(ShardIdFull dst);
|
||||
|
||||
std::map<ShardIdFull, td::actor::ActorOwn<FullNodeShard>> shards_;
|
||||
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
td::actor::ActorId<adnl::Adnl> adnl_;
|
||||
td::actor::ActorId<rldp::Rldp> rldp_;
|
||||
td::actor::ActorId<dht::Dht> dht_;
|
||||
td::actor::ActorId<overlay::Overlays> overlays_;
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager_;
|
||||
|
||||
std::string db_root_;
|
||||
|
||||
PublicKeyHash sign_cert_by_;
|
||||
std::vector<PublicKeyHash> all_validators_;
|
||||
|
||||
std::set<PublicKeyHash> local_keys_;
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
91
validator/get-next-key-blocks.cpp
Normal file
91
validator/get-next-key-blocks.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "get-next-key-blocks.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
void GetNextKeyBlocks::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(res_));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void GetNextKeyBlocks::abort_query(td::Status error) {
|
||||
if (promise_) {
|
||||
promise_.set_error(std::move(error));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void GetNextKeyBlocks::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void GetNextKeyBlocks::start_up() {
|
||||
if (!block_id_.is_masterchain()) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "block is not from masterchain"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_id_.id.seqno > last_known_key_block_->id().seqno()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_id_.id.seqno == last_known_key_block_->id().seqno()) {
|
||||
if (block_id_ == last_known_key_block_->id()) {
|
||||
finish_query();
|
||||
} else {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad block id"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_id_.seqno() > 0) {
|
||||
BlockIdExt block_id;
|
||||
auto f = masterchain_state_->prev_key_block_id(block_id_.seqno());
|
||||
if (!f.is_valid()) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad block id (not key?)"));
|
||||
return;
|
||||
} else if (f != block_id_) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad block id (not key?) 2"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (res_.size() < limit_) {
|
||||
auto b = masterchain_state_->next_key_block_id(block_id_.seqno() + 1);
|
||||
if (b.is_valid()) {
|
||||
res_.push_back(b);
|
||||
block_id_ = b;
|
||||
} else {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
finish_query();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
64
validator/get-next-key-blocks.h
Normal file
64
validator/get-next-key-blocks.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class GetNextKeyBlocks : public td::actor::Actor {
|
||||
public:
|
||||
GetNextKeyBlocks(BlockIdExt block_id, td::uint32 limit, BlockHandle last_known_key_block,
|
||||
td::Ref<MasterchainState> masterchain_state, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<std::vector<BlockIdExt>> promise)
|
||||
: block_id_(block_id)
|
||||
, limit_(limit)
|
||||
, last_known_key_block_(std::move(last_known_key_block))
|
||||
, masterchain_state_(std::move(masterchain_state))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
|
||||
void finish_query();
|
||||
void abort_query(td::Status error);
|
||||
void alarm() override;
|
||||
|
||||
private:
|
||||
BlockIdExt block_id_;
|
||||
td::uint32 limit_;
|
||||
|
||||
BlockHandle last_known_key_block_;
|
||||
td::Ref<MasterchainState> masterchain_state_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
|
||||
td::Promise<std::vector<BlockIdExt>> promise_;
|
||||
|
||||
std::vector<BlockIdExt> res_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
52
validator/impl/CMakeLists.txt
Normal file
52
validator/impl/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
set(TON_VALIDATOR_SOURCE
|
||||
accept-block.cpp
|
||||
block.cpp
|
||||
check-proof.cpp
|
||||
collator.cpp
|
||||
external-message.cpp
|
||||
fabric.cpp
|
||||
ihr-message.cpp
|
||||
liteserver.cpp
|
||||
message-queue.cpp
|
||||
proof.cpp
|
||||
shard.cpp
|
||||
signature-set.cpp
|
||||
top-shard-descr.cpp
|
||||
validate-query.cpp
|
||||
validator-set.cpp
|
||||
|
||||
accept-block.hpp
|
||||
block.hpp
|
||||
check-proof.hpp
|
||||
collate-query-impl.h
|
||||
collator-impl.h
|
||||
collator.h
|
||||
external-message.hpp
|
||||
ihr-message.hpp
|
||||
liteserver.hpp
|
||||
message-queue.hpp
|
||||
proof.hpp
|
||||
shard.hpp
|
||||
signature-set.hpp
|
||||
top-shard-descr.hpp
|
||||
validate-query.hpp
|
||||
validator-set.hpp
|
||||
)
|
||||
|
||||
add_library(ton_validator STATIC ${TON_VALIDATOR_SOURCE})
|
||||
|
||||
target_include_directories(ton_validator PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../crypto
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(ton_validator PRIVATE tdutils tdactor adnl tl_api tl_lite_api tl-lite-utils dht tdfec
|
||||
overlay catchain validatorsession ton_crypto ton_block)
|
||||
820
validator/impl/accept-block.cpp
Normal file
820
validator/impl/accept-block.cpp
Normal file
|
|
@ -0,0 +1,820 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "accept-block.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
#include "fabric.h"
|
||||
#include "top-shard-descr.hpp"
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "vm/boc.h"
|
||||
#include "block/block.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
|
||||
#include "validator/invariants.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
AcceptBlockQuery::AcceptBlockQuery(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
|
||||
bool send_broadcast, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise)
|
||||
: id_(id)
|
||||
, data_(std::move(data))
|
||||
, prev_(std::move(prev))
|
||||
, validator_set_(std::move(validator_set))
|
||||
, signatures_(std::move(signatures))
|
||||
, is_fake_(false)
|
||||
, send_broadcast_(send_broadcast)
|
||||
, manager_(manager)
|
||||
, promise_(std::move(promise)) {
|
||||
state_keep_old_hash_.clear();
|
||||
state_old_hash_.clear();
|
||||
state_hash_.clear();
|
||||
CHECK(prev_.size() > 0);
|
||||
}
|
||||
|
||||
AcceptBlockQuery::AcceptBlockQuery(AcceptBlockQuery::IsFake fake, BlockIdExt id, td::Ref<BlockData> data,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise)
|
||||
: id_(id)
|
||||
, data_(std::move(data))
|
||||
, prev_(std::move(prev))
|
||||
, validator_set_(std::move(validator_set))
|
||||
, is_fake_(true)
|
||||
, send_broadcast_(false)
|
||||
, manager_(manager)
|
||||
, promise_(std::move(promise)) {
|
||||
state_keep_old_hash_.clear();
|
||||
state_old_hash_.clear();
|
||||
state_hash_.clear();
|
||||
CHECK(prev_.size() > 0);
|
||||
}
|
||||
|
||||
bool AcceptBlockQuery::create_new_proof() {
|
||||
// 0. check block's root hash
|
||||
VLOG(VALIDATOR_DEBUG) << "create_new_proof() : start";
|
||||
RootHash blk_rhash{block_root_->get_hash().bits()};
|
||||
if (blk_rhash != id_.root_hash) {
|
||||
return fatal_error("block root hash mismatch: expected "s + id_.root_hash.to_hex() + ", found " +
|
||||
blk_rhash.to_hex());
|
||||
}
|
||||
// 1. visit block header while building a Merkle proof
|
||||
auto usage_tree = std::make_shared<vm::CellUsageTree>();
|
||||
auto usage_cell = vm::UsageCell::create(block_root_, usage_tree->root_ptr());
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::ExtBlkRef::Record mcref{}; // _ ExtBlkRef = BlkMasterInfo;
|
||||
block::CurrencyCollection fees;
|
||||
ShardIdFull shard;
|
||||
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no &&
|
||||
block::gen::BlkPrevInfo{info.after_merge}.validate_ref(info.prev_ref) &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
(!info.not_master || tlb::unpack_cell(info.master_ref, mcref)))) {
|
||||
return fatal_error("cannot unpack block header");
|
||||
}
|
||||
is_key_block_ = info.key_block;
|
||||
// 2. check some header fields, especially shard
|
||||
if (info.not_master != !shard.is_masterchain()) {
|
||||
return fatal_error("block has invalid not_master flag in its header");
|
||||
}
|
||||
BlockId blk_id{shard, (unsigned)info.seq_no};
|
||||
if (blk_id != id_.id) {
|
||||
return fatal_error("block header corresponds to another block id: expected "s + id_.id.to_str() + ", found " +
|
||||
blk_id.to_str());
|
||||
}
|
||||
if (info.after_merge + 1U != prev_.size()) {
|
||||
return fatal_error(PSTRING() << "block header of " << id_.to_str() << " announces " << info.after_merge + 1
|
||||
<< " previous blocks, but " << prev_.size() << " are actually present");
|
||||
}
|
||||
if (is_masterchain() && (info.after_merge | info.after_split | info.before_split)) {
|
||||
return fatal_error("masterchain block header of "s + id_.to_str() + " announces merge/split in its header");
|
||||
}
|
||||
if (!is_masterchain() && is_key_block_) {
|
||||
return fatal_error("non-masterchain block header of "s + id_.to_str() + " announces this block to be a key block");
|
||||
}
|
||||
// 3. check state update
|
||||
vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update};
|
||||
if (!(upd_cs.is_special() && upd_cs.prefetch_long(8) == 4 // merkle update
|
||||
&& upd_cs.size_ext() == 0x20228)) {
|
||||
return fatal_error("invalid Merkle update in block");
|
||||
}
|
||||
// 4. visit validator-set related fields in key blocks
|
||||
if (is_key_block_) {
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
mc_extra.key_block && mc_extra.config.not_null())) {
|
||||
return fatal_error("cannot unpack extra header of key masterchain block "s + blk_id.to_str());
|
||||
}
|
||||
auto cfg = block::Config::unpack_config(std::move(mc_extra.config));
|
||||
if (cfg.is_error()) {
|
||||
return fatal_error("cannot extract configuration from extra header of key masterchain block "s + blk_id.to_str() +
|
||||
" : " + cfg.move_as_error().to_string());
|
||||
}
|
||||
auto res = cfg.move_as_ok()->visit_validator_params();
|
||||
if (res.is_error()) {
|
||||
return fatal_error("cannot extract validator set configuration from extra header of key masterchain block "s +
|
||||
blk_id.to_str() + " : " + res.to_string());
|
||||
}
|
||||
}
|
||||
// 5. finish constructing Merkle proof from visited cells
|
||||
auto proof = vm::MerkleProof::generate(block_root_, usage_tree.get());
|
||||
proof_roots_.push_back(proof);
|
||||
// 6. extract some information from state update
|
||||
state_old_hash_ = upd_cs.prefetch_ref(0)->get_hash(0).bits();
|
||||
state_hash_ = upd_cs.prefetch_ref(1)->get_hash(0).bits();
|
||||
lt_ = info.end_lt;
|
||||
created_at_ = info.gen_utime;
|
||||
if (!is_masterchain()) {
|
||||
mc_blkid_.id = BlockId{masterchainId, shardIdAll, mcref.seq_no};
|
||||
mc_blkid_.root_hash = mcref.root_hash;
|
||||
mc_blkid_.file_hash = mcref.file_hash;
|
||||
} else if (!is_key_block_) {
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
!mc_extra.key_block)) {
|
||||
return fatal_error("extra header of non-key masterchain block "s + blk_id.to_str() +
|
||||
" is invalid or contains extra information reserved for key blocks only");
|
||||
}
|
||||
}
|
||||
// 7. check signatures
|
||||
td::Result<td::uint64> sign_chk;
|
||||
if (!is_fake_) {
|
||||
sign_chk = validator_set_->check_signatures(id_.root_hash, id_.file_hash, signatures_);
|
||||
if (sign_chk.is_error()) {
|
||||
auto err = sign_chk.move_as_error();
|
||||
VLOG(VALIDATOR_WARNING) << "signature check failed : " << err.to_string();
|
||||
abort_query(std::move(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 8. serialize signatures
|
||||
if (!is_fake_) {
|
||||
vm::CellBuilder cb2;
|
||||
Ref<vm::Cell> sign_cell;
|
||||
if (!(cb2.store_long_bool(0x11, 8) // block_signatures#11
|
||||
&& cb2.store_long_bool(validator_set_->get_validator_set_hash(),
|
||||
32) // validator_info$_ validator_set_hash_short:uint32
|
||||
&& cb2.store_long_bool(validator_set_->get_catchain_seqno(),
|
||||
32) // validator_set_ts:uint32 = ValidatorInfo
|
||||
&& cb2.store_long_bool(signatures_->size(), 32) // sig_count:uint32
|
||||
&& cb2.store_long_bool(sign_chk.move_as_ok(), 64) // sig_weight:uint32
|
||||
&& signatures_->serialize_to(sign_cell) // (HashmapE 16 CryptoSignaturePair)
|
||||
&& cb2.store_maybe_ref(std::move(sign_cell)) && cb2.finalize_to(signatures_cell_))) {
|
||||
return fatal_error("cannot serialize BlockSignatures for the newly-accepted block");
|
||||
}
|
||||
} else { // FAKE
|
||||
vm::CellBuilder cb2;
|
||||
if (!(cb2.store_long_bool(0x11, 8) // block_signatures#11
|
||||
&& cb2.store_long_bool(validator_set_->get_validator_set_hash(),
|
||||
32) // validator_info$_ validator_set_hash_short:uint32
|
||||
&& cb2.store_long_bool(validator_set_->get_catchain_seqno(),
|
||||
32) // validator_set_ts:uint32 = ValidatorInfo
|
||||
&& cb2.store_long_bool(0, 32) // sig_count:uint32
|
||||
&& cb2.store_long_bool(0, 64) // sig_weight:uint32
|
||||
&& cb2.store_bool_bool(false) // (HashmapE 16 CryptoSignaturePair)
|
||||
&& cb2.finalize_to(signatures_cell_))) {
|
||||
return fatal_error("cannot serialize fake BlockSignatures for the newly-accepted block");
|
||||
}
|
||||
}
|
||||
Ref<vm::Cell> bs_cell;
|
||||
if (is_masterchain()) {
|
||||
// 9a. now create serialized proof
|
||||
vm::CellBuilder cb;
|
||||
if (!(cb.store_long_bool(0xc3, 8) // block_proof#c3
|
||||
&& block::tlb::t_BlockIdExt.pack(cb, id_) // proof_for:BlockIdExt
|
||||
&& cb.store_ref_bool(std::move(proof)) // proof:^Cell
|
||||
&& cb.store_bool_bool(true) // signatures:(Maybe
|
||||
&& cb.store_ref_bool(signatures_cell_) // ^BlockSignatures)
|
||||
&& cb.finalize_to(bs_cell))) {
|
||||
return fatal_error("cannot serialize BlockProof for the newly-accepted block");
|
||||
}
|
||||
} else {
|
||||
// 9b. create serialized proof (link)
|
||||
vm::CellBuilder cb;
|
||||
if (!(cb.store_long_bool(0xc3, 8) // block_proof#c3
|
||||
&& block::tlb::t_BlockIdExt.pack(cb, id_) // proof_for:BlockIdExt
|
||||
&& cb.store_ref_bool(std::move(proof)) // proof:^Cell
|
||||
&& cb.store_bool_bool(false) // signatures:(Maybe ^BlockSignatures)
|
||||
&& cb.finalize_to(bs_cell))) {
|
||||
return fatal_error("cannot serialize BlockProof for the newly-accepted block");
|
||||
}
|
||||
}
|
||||
// 10. check resulting object
|
||||
if (!block::gen::t_BlockProof.validate_ref(bs_cell)) {
|
||||
block::gen::t_BlockProof.print_ref(std::cerr, bs_cell);
|
||||
vm::load_cell_slice(bs_cell).print_rec(std::cerr);
|
||||
return fatal_error("BlockProof object just created failed to pass automated consistency checks");
|
||||
}
|
||||
// 11. create a proof object from this cell
|
||||
if (is_masterchain()) {
|
||||
proof_ = create_proof(id_, vm::std_boc_serialize(bs_cell, 0).move_as_ok()).move_as_ok();
|
||||
} else {
|
||||
proof_link_ = create_proof_link(id_, vm::std_boc_serialize(bs_cell, 0).move_as_ok()).move_as_ok();
|
||||
}
|
||||
VLOG(VALIDATOR_DEBUG) << "create_new_proof() : end";
|
||||
return true;
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
VLOG(VALIDATOR_WARNING) << "aborting accept block query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
bool AcceptBlockQuery::fatal_error(std::string msg, int code) {
|
||||
abort_query(td::Status::Error(code, std::move(msg)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AcceptBlockQuery::check_send_error(td::actor::ActorId<AcceptBlockQuery> SelfId, td::Status error) {
|
||||
if (error.is_error()) {
|
||||
td::actor::send_closure(std::move(SelfId), &AcceptBlockQuery::abort_query, std::move(error));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::finish_query() {
|
||||
ValidatorInvariants::check_post_accept(handle_);
|
||||
if (is_masterchain()) {
|
||||
CHECK(handle_->inited_proof());
|
||||
} else {
|
||||
CHECK(handle_->inited_proof_link());
|
||||
}
|
||||
if (promise_) {
|
||||
promise_.set_value(td::Unit());
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::start_up() {
|
||||
VLOG(VALIDATOR_DEBUG) << "start_up()";
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
if (validator_set_.is_null()) {
|
||||
fatal_error("no real ValidatorSet passed to AcceptBlockQuery");
|
||||
return;
|
||||
}
|
||||
if (!is_fake_ && signatures_.is_null()) {
|
||||
fatal_error("no real SignatureSet passed to AcceptBlockQuery");
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::get_block_handle, id_, true, [SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_block_handle, R.move_as_ok());
|
||||
});
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_block_handle(BlockHandle handle) {
|
||||
VLOG(VALIDATOR_DEBUG) << "got_block_handle()";
|
||||
handle_ = std::move(handle);
|
||||
if (handle_->received() && handle_->received_state() && handle_->inited_signatures() &&
|
||||
handle_->inited_split_after() && handle_->inited_merge_before() && handle_->inited_prev() &&
|
||||
handle_->inited_logical_time() && handle_->inited_state_root_hash() &&
|
||||
(is_masterchain() ? handle_->inited_proof() && handle_->is_applied() && handle_->inited_is_key_block()
|
||||
: handle_->inited_proof_link())) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
if (data_.not_null() && !handle_->received()) {
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::set_block_data, handle_, data_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_data);
|
||||
});
|
||||
} else {
|
||||
written_block_data();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_data() {
|
||||
VLOG(VALIDATOR_DEBUG) << "written_block_data()";
|
||||
if (handle_->inited_signatures()) {
|
||||
written_block_signatures();
|
||||
return;
|
||||
}
|
||||
if (is_fake_) {
|
||||
signatures_ = Ref<BlockSignatureSetQ>(create_signature_set(std::vector<BlockSignature>{}));
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_signatures, handle_, signatures_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_signatures);
|
||||
});
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_signatures() {
|
||||
VLOG(VALIDATOR_DEBUG) << "written_block_signatures()";
|
||||
handle_->set_merge(prev_.size() == 2);
|
||||
|
||||
for (auto& p : prev_) {
|
||||
handle_->set_prev(p);
|
||||
}
|
||||
|
||||
if (handle_->need_flush()) {
|
||||
handle_->flush(manager_, handle_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_info);
|
||||
});
|
||||
} else {
|
||||
written_block_info();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_info() {
|
||||
VLOG(VALIDATOR_DEBUG) << "written block info";
|
||||
if (data_.not_null()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_prev_state, R.move_as_ok());
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_prev_block_state, handle_, priority(), timeout_,
|
||||
std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, priority(), timeout_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_block_data,
|
||||
R.move_as_ok());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_block_data(td::Ref<BlockData> data) {
|
||||
VLOG(VALIDATOR_DEBUG) << "got_block_data()";
|
||||
data_ = std::move(data);
|
||||
CHECK(data_.not_null());
|
||||
if (data_->root_cell().is_null()) {
|
||||
fatal_error("block data does not contain a root cell");
|
||||
return;
|
||||
}
|
||||
if (handle_->received()) {
|
||||
written_block_data();
|
||||
} else {
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::set_block_data, handle_, data_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_prev_state(td::Ref<ShardState> state) {
|
||||
VLOG(VALIDATOR_DEBUG) << "got prev state";
|
||||
state_ = std::move(state);
|
||||
|
||||
state_keep_old_hash_ = state_->root_hash();
|
||||
|
||||
auto err = state_.write().apply_block(id_, data_);
|
||||
if (err.is_error()) {
|
||||
abort_query(std::move(err));
|
||||
return;
|
||||
}
|
||||
|
||||
handle_->set_split(state_->before_split());
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, state_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_state, R.move_as_ok());
|
||||
});
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_state(td::Ref<ShardState> upd_state) {
|
||||
VLOG(VALIDATOR_DEBUG) << "written state";
|
||||
CHECK(data_.not_null());
|
||||
state_ = std::move(upd_state);
|
||||
|
||||
block_root_ = data_->root_cell();
|
||||
if (block_root_.is_null()) {
|
||||
fatal_error("block data does not contain a root cell");
|
||||
return;
|
||||
}
|
||||
// generate proof
|
||||
if (!create_new_proof()) {
|
||||
fatal_error("cannot generate proof for block "s + id_.to_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (state_keep_old_hash_ != state_old_hash_) {
|
||||
fatal_error(PSTRING() << "invalid previous state hash in newly-created proof: expected "
|
||||
<< state_->root_hash().to_hex() << ", found in update " << state_old_hash_.to_hex());
|
||||
return;
|
||||
}
|
||||
|
||||
//handle_->set_masterchain_block(prev_[0]);
|
||||
handle_->set_state_root_hash(state_hash_);
|
||||
handle_->set_logical_time(lt_);
|
||||
handle_->set_unix_time(created_at_);
|
||||
handle_->set_is_key_block(is_key_block_);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_proof);
|
||||
});
|
||||
|
||||
if (is_masterchain()) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof, handle_, proof_, std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_proof_link, handle_, proof_link_, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_proof() {
|
||||
VLOG(VALIDATOR_DEBUG) << "written_block_proof()";
|
||||
if (!is_masterchain()) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_top_masterchain_state_block,
|
||||
[SelfId = actor_id(this)](td::Result<std::pair<td::Ref<MasterchainState>, BlockIdExt>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_last_mc_block,
|
||||
R.move_as_ok());
|
||||
});
|
||||
return;
|
||||
}
|
||||
CHECK(prev_.size() == 1);
|
||||
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::set_next_block, prev_[0], id_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_next);
|
||||
});
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_last_mc_block(std::pair<td::Ref<MasterchainState>, BlockIdExt> last) {
|
||||
VLOG(VALIDATOR_DEBUG) << "got_last_mc_block(): " << last.second.to_str();
|
||||
last_mc_state_ = Ref<MasterchainStateQ>(std::move(last.first));
|
||||
last_mc_id_ = std::move(last.second);
|
||||
CHECK(last_mc_state_.not_null());
|
||||
if (last_mc_id_.id.seqno < mc_blkid_.id.seqno) {
|
||||
VLOG(VALIDATOR_DEBUG) << "shardchain block refers to newer masterchain block " << mc_blkid_.to_str()
|
||||
<< ", trying to obtain it";
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(), timeout_,
|
||||
[SelfId = actor_id(this)](td::Result<Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_mc_state,
|
||||
R.move_as_ok());
|
||||
});
|
||||
return;
|
||||
} else if (last_mc_id_.id.seqno > mc_blkid_.id.seqno) {
|
||||
if (!last_mc_state_->check_old_mc_block_id(mc_blkid_)) {
|
||||
fatal_error("shardchain block refers to masterchain block "s + mc_blkid_.to_str() +
|
||||
" which is not a antecessor of last masterchain block " + last_mc_id_.to_str());
|
||||
return;
|
||||
}
|
||||
} else if (last_mc_id_ != mc_blkid_) {
|
||||
fatal_error("shardchain block refers to masterchain block "s + mc_blkid_.to_str() +
|
||||
" distinct from last masterchain block " + last_mc_id_.to_str() + " of the same height");
|
||||
return;
|
||||
}
|
||||
find_known_ancestors();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_mc_state(Ref<ShardState> res) {
|
||||
VLOG(VALIDATOR_DEBUG) << "got_mc_state()";
|
||||
auto new_state = Ref<MasterchainStateQ>(std::move(res));
|
||||
CHECK(new_state.not_null());
|
||||
if (!new_state->check_old_mc_block_id(last_mc_id_)) {
|
||||
fatal_error("shardchain block refers to masterchain block "s + mc_blkid_.to_str() +
|
||||
" which is not a successor of last masterchain block " + last_mc_id_.to_str());
|
||||
return;
|
||||
}
|
||||
last_mc_id_ = mc_blkid_;
|
||||
last_mc_state_ = std::move(new_state);
|
||||
find_known_ancestors();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::find_known_ancestors() {
|
||||
VLOG(VALIDATOR_DEBUG) << "find_known_ancestors()";
|
||||
prev_mc_blkid_ = mc_blkid_;
|
||||
auto config = last_mc_state_->get_config();
|
||||
CHECK(config);
|
||||
auto shard = ton::ShardIdFull(id_);
|
||||
auto ancestor = config->get_shard_hash(shard, false);
|
||||
if (ancestor.is_null()) {
|
||||
ancestor = config->get_shard_hash(ton::shard_child(shard, true));
|
||||
auto ancestor2 = config->get_shard_hash(ton::shard_child(shard, false));
|
||||
if (ancestor.is_null() || ancestor2.is_null()) {
|
||||
VLOG(VALIDATOR_WARNING) << " cannot retrieve information about shard " + shard.to_str() +
|
||||
" from masterchain block " + last_mc_id_.to_str() +
|
||||
", skipping ShardTopBlockDescr creation";
|
||||
if (last_mc_id_.id.seqno <= mc_blkid_.id.seqno) {
|
||||
fatal_error(" cannot retrieve information about shard "s + shard.to_str() + " from masterchain block " +
|
||||
last_mc_id_.to_str());
|
||||
return;
|
||||
}
|
||||
written_block_next();
|
||||
return;
|
||||
}
|
||||
VLOG(VALIDATOR_DEBUG) << "found two ancestors: " << ancestor->blk_.to_str() << " and " << ancestor2->blk_.to_str();
|
||||
ancestors_seqno_ = std::max(ancestor->blk_.id.seqno, ancestor2->blk_.id.seqno);
|
||||
ancestors_.emplace_back(std::move(ancestor));
|
||||
ancestors_.emplace_back(std::move(ancestor2));
|
||||
} else if (ancestor->shard() == shard) {
|
||||
VLOG(VALIDATOR_DEBUG) << "found one regular ancestor " << ancestor->blk_.to_str();
|
||||
ancestors_seqno_ = ancestor->seqno();
|
||||
ancestors_.emplace_back(std::move(ancestor));
|
||||
} else if (ton::shard_is_parent(ancestor->shard(), shard)) {
|
||||
VLOG(VALIDATOR_DEBUG) << "found one parent ancestor " << ancestor->blk_.to_str();
|
||||
ancestors_seqno_ = ancestor->seqno();
|
||||
ancestors_.emplace_back(std::move(ancestor));
|
||||
ancestors_split_ = true;
|
||||
} else {
|
||||
VLOG(VALIDATOR_WARNING) << " cannot retrieve information about shard " + shard.to_str() +
|
||||
" from masterchain block " + last_mc_id_.to_str() +
|
||||
", skipping ShardTopBlockDescr creation";
|
||||
if (last_mc_id_.id.seqno <= mc_blkid_.id.seqno || ancestor->seqno() <= id_.id.seqno) {
|
||||
fatal_error(" cannot retrieve information about shard "s + shard.to_str() + " from masterchain block " +
|
||||
last_mc_id_.to_str());
|
||||
return;
|
||||
}
|
||||
written_block_next();
|
||||
return;
|
||||
}
|
||||
if (ancestors_seqno_ >= id_.id.seqno) {
|
||||
VLOG(VALIDATOR_WARNING) << "skipping ShardTopBlockDescr creation for " << id_.to_str() << " because a newer block "
|
||||
<< ancestors_.at(0)->blk_.to_str() << " is already present in masterchain block "
|
||||
<< last_mc_id_.to_str();
|
||||
written_block_next();
|
||||
return;
|
||||
}
|
||||
if (id_.id.seqno > ancestors_seqno_ + 8) {
|
||||
fatal_error("cannot accept shardchain block "s + id_.to_str() +
|
||||
" because it requires including a chain of more than eight new shardchain blocks");
|
||||
return;
|
||||
}
|
||||
if (id_.id.seqno == ancestors_seqno_ + 1) {
|
||||
create_topshard_blk_descr();
|
||||
return;
|
||||
}
|
||||
CHECK(prev_.size() == 1);
|
||||
require_proof_link(prev_[0]);
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::require_proof_link(BlockIdExt id) {
|
||||
VLOG(VALIDATOR_DEBUG) << "require_proof_link(" << id.to_str() << ")";
|
||||
CHECK(ton::ShardIdFull(id) == ton::ShardIdFull(id_));
|
||||
CHECK(id.id.seqno == id_.id.seqno - 1 - proof_links_.size());
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_proof_link_short, id, timeout_,
|
||||
[SelfId = actor_id(this), id](td::Result<Ref<ProofLink>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_proof_link, id,
|
||||
R.move_as_ok());
|
||||
});
|
||||
}
|
||||
|
||||
bool AcceptBlockQuery::unpack_proof_link(BlockIdExt id, Ref<ProofLink> proof_link) {
|
||||
auto res0 = vm::std_boc_deserialize(proof_link->data());
|
||||
if (res0.is_error()) {
|
||||
return fatal_error("cannot deserialize proof link for "s + id.to_str() + ": " + res0.move_as_error().to_string());
|
||||
}
|
||||
Ref<vm::Cell> proof_root = res0.move_as_ok();
|
||||
block::gen::BlockProof::Record proof;
|
||||
BlockIdExt proof_blk_id;
|
||||
if (!(tlb::unpack_cell(proof_root, proof) &&
|
||||
block::tlb::t_BlockIdExt.unpack(proof.proof_for.write(), proof_blk_id))) {
|
||||
return false;
|
||||
}
|
||||
if (proof_blk_id != id) {
|
||||
return fatal_error("block proof link is for another block: expected "s + id.to_str() + ", found " +
|
||||
proof_blk_id.to_str());
|
||||
}
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof.root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() +
|
||||
" does not contain a valid Merkle proof for the block header");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != id.root_hash) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() +
|
||||
" contains a Merkle proof with incorrect root hash: expected " + id.root_hash.to_hex() +
|
||||
", found " + virt_hash.to_hex());
|
||||
}
|
||||
bool after_split;
|
||||
BlockIdExt mc_blkid;
|
||||
auto res = block::unpack_block_prev_blk_try(virt_root, id, link_prev_, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
return fatal_error("error in block header in proof link for "s + id.to_str() + ": " +
|
||||
res.move_as_error().to_string());
|
||||
}
|
||||
if (mc_blkid.id.seqno > prev_mc_blkid_.id.seqno) {
|
||||
return fatal_error("previous shardchain block "s + id.to_str() + " refers to a newer masterchain block " +
|
||||
mc_blkid.id.to_str() + " than that referred to by the next one: " + prev_mc_blkid_.id.to_str());
|
||||
} else if (mc_blkid.id.seqno < prev_mc_blkid_.id.seqno) {
|
||||
if (!last_mc_state_->check_old_mc_block_id(mc_blkid)) {
|
||||
return fatal_error(
|
||||
"previous shardchain block "s + id.to_str() + " refers to masterchain block " + mc_blkid.id.to_str() +
|
||||
" which is not an ancestor of that referred to by the next one: " + prev_mc_blkid_.id.to_str());
|
||||
}
|
||||
prev_mc_blkid_ = mc_blkid;
|
||||
} else if (mc_blkid != prev_mc_blkid_) {
|
||||
return fatal_error("previous shardchain block "s + id.to_str() + " refers to masterchain block " +
|
||||
mc_blkid.id.to_str() +
|
||||
" with the same height as, but distinct from that referred to by the next shardchain block: " +
|
||||
prev_mc_blkid_.id.to_str());
|
||||
}
|
||||
try {
|
||||
block::gen::Block::Record block;
|
||||
if (!(tlb::unpack_cell(virt_root, block) && block::gen::t_ValueFlow.force_validate_ref(block.value_flow))) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() + " does not contain value flow information");
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return fatal_error("error unpacking proof link for block "s + id.to_str() + " : " + err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return fatal_error("virtualization error unpacking proof link for block "s + id.to_str() + " : " + err.get_msg());
|
||||
}
|
||||
proof_roots_.push_back(std::move(proof.root));
|
||||
return true;
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::got_proof_link(BlockIdExt id, Ref<ProofLink> proof) {
|
||||
VLOG(VALIDATOR_DEBUG) << "got_proof_link(" << id.to_str() << ")";
|
||||
CHECK(proof.not_null());
|
||||
proof_links_.push_back(proof);
|
||||
if (!unpack_proof_link(id, std::move(proof))) {
|
||||
fatal_error("cannot unpack proof link for "s + id.to_str());
|
||||
return;
|
||||
}
|
||||
if (id.id.seqno == ancestors_seqno_ + 1) {
|
||||
// first link in chain
|
||||
if (ancestors_.size() != link_prev_.size() || ancestors_[0]->blk_ != link_prev_[0] ||
|
||||
(ancestors_.size() == 2 && ancestors_[1]->blk_ != link_prev_[1])) {
|
||||
fatal_error("invalid first link at block "s + id.to_str() + " for shardchain block " + id_.to_str());
|
||||
return;
|
||||
}
|
||||
create_topshard_blk_descr();
|
||||
} else {
|
||||
CHECK(id.id.seqno > ancestors_seqno_);
|
||||
// intermediate link
|
||||
if (link_prev_.size() != 1 || ton::ShardIdFull(link_prev_[0].id) != ton::ShardIdFull(id_) ||
|
||||
link_prev_[0].id.seqno + 1 != id.id.seqno) {
|
||||
fatal_error("invalid intermediate link at block "s + id.to_str() + " for shardchain block " + id_.to_str());
|
||||
return;
|
||||
}
|
||||
require_proof_link(link_prev_[0]);
|
||||
}
|
||||
}
|
||||
|
||||
bool AcceptBlockQuery::create_top_shard_block_description() {
|
||||
VLOG(VALIDATOR_DEBUG) << "create_top_shard_block_description()";
|
||||
CHECK(proof_roots_.size() == proof_links_.size() + 1);
|
||||
int n = (int)proof_roots_.size();
|
||||
CHECK(n <= 8);
|
||||
Ref<vm::Cell> root;
|
||||
for (int i = n - 1; i > 0; i--) {
|
||||
vm::CellBuilder cb;
|
||||
if (!(cb.store_ref_bool(proof_roots_[i]) && (root.is_null() || cb.store_ref_bool(root)) && cb.finalize_to(root))) {
|
||||
return fatal_error("error serializing ProofChain");
|
||||
}
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> td_cell;
|
||||
if (!(cb.store_long_bool(0xd5, 8) // top_block_descr#d5
|
||||
&& block::tlb::t_BlockIdExt.pack(cb, id_) // proof_for:BlockIdExt
|
||||
&& cb.store_bool_bool(true) // signatures:(Maybe
|
||||
&& cb.store_ref_bool(signatures_cell_) // ^BlockSignatures)
|
||||
&& cb.store_long_bool(n, 8) // len:(## 8)
|
||||
&& n <= 8 // { len <= 8 }
|
||||
&& cb.store_ref_bool(proof_roots_[0]) // chain:(ProofChain len)
|
||||
&& (root.is_null() || cb.store_ref_bool(std::move(root))) && cb.finalize_to(td_cell))) {
|
||||
return fatal_error("cannot serialize ShardTopBlockDescription for the newly-accepted block "s + id_.to_str());
|
||||
}
|
||||
if (false) {
|
||||
// debug output
|
||||
std::cerr << "new ShardTopBlockDescription: ";
|
||||
block::gen::t_TopBlockDescr.print_ref(std::cerr, td_cell);
|
||||
vm::load_cell_slice(td_cell).print_rec(std::cerr);
|
||||
}
|
||||
if (!block::gen::t_TopBlockDescr.validate_ref(td_cell)) {
|
||||
block::gen::t_TopBlockDescr.print_ref(std::cerr, td_cell);
|
||||
vm::load_cell_slice(td_cell).print_rec(std::cerr);
|
||||
return fatal_error("just created ShardTopBlockDescription for "s + id_.to_str() + " is invalid");
|
||||
}
|
||||
auto res = vm::std_boc_serialize(td_cell, 0);
|
||||
if (res.is_error()) {
|
||||
return fatal_error("cannot serialize a ShardTopBlockDescription object for "s + id_.to_str() + ": " +
|
||||
res.move_as_error().to_string());
|
||||
}
|
||||
top_block_descr_data_ = res.move_as_ok();
|
||||
VLOG(VALIDATOR_DEBUG) << "create_top_shard_block_description() : end";
|
||||
return true;
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::create_topshard_blk_descr() {
|
||||
VLOG(VALIDATOR_DEBUG) << "create_topshard_blk_descr()";
|
||||
// generate top shard block description
|
||||
if (!create_top_shard_block_description()) {
|
||||
fatal_error("cannot generate top shard block description for "s + id_.to_str());
|
||||
return;
|
||||
}
|
||||
CHECK(top_block_descr_data_.size());
|
||||
td::actor::create_actor<ValidateShardTopBlockDescr>(
|
||||
"topshardfetchchk", std::move(top_block_descr_data_), last_mc_id_, BlockHandle{}, last_mc_state_, manager_,
|
||||
timeout_, is_fake_,
|
||||
[SelfId = actor_id(this)](td::Result<Ref<ShardTopBlockDescription>> R) {
|
||||
td::actor::send_closure_later(SelfId, &AcceptBlockQuery::top_block_descr_validated, std::move(R));
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::top_block_descr_validated(td::Result<Ref<ShardTopBlockDescription>> R) {
|
||||
VLOG(VALIDATOR_DEBUG) << "top_block_descr_validated()";
|
||||
if (R.is_error()) {
|
||||
VLOG(VALIDATOR_WARNING) << "error validating newly-created ShardTopBlockDescr for " << id_.to_str() << ": "
|
||||
<< R.move_as_error().to_string();
|
||||
} else {
|
||||
top_block_descr_ = R.move_as_ok();
|
||||
CHECK(top_block_descr_.not_null());
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::send_top_shard_block_description, top_block_descr_);
|
||||
}
|
||||
written_block_next();
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_next() {
|
||||
VLOG(VALIDATOR_DEBUG) << "written_block_next()";
|
||||
if (handle_->need_flush()) {
|
||||
handle_->flush(manager_, handle_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_info_2);
|
||||
});
|
||||
} else {
|
||||
written_block_info_2();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::written_block_info_2() {
|
||||
VLOG(VALIDATOR_DEBUG) << "written_block_info_2()";
|
||||
if (handle_->id().is_masterchain()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::applied);
|
||||
});
|
||||
run_apply_block_query(handle_->id(), data_, manager_, timeout_, std::move(P));
|
||||
} else {
|
||||
applied();
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptBlockQuery::applied() {
|
||||
if (!send_broadcast_) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
BlockBroadcast b;
|
||||
b.data = data_->data();
|
||||
b.block_id = id_;
|
||||
std::vector<BlockSignature> sigs;
|
||||
if (!is_fake_) {
|
||||
for (auto& v : signatures_->signatures()) {
|
||||
sigs.emplace_back(BlockSignature{v.node, v.signature.clone()});
|
||||
}
|
||||
}
|
||||
b.signatures = std::move(sigs);
|
||||
b.catchain_seqno = validator_set_->get_catchain_seqno();
|
||||
b.validator_set_hash = validator_set_->get_validator_set_hash();
|
||||
if (is_masterchain()) {
|
||||
b.proof = proof_->data();
|
||||
} else {
|
||||
b.proof = proof_link_->data();
|
||||
}
|
||||
|
||||
// do not wait for answer
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::send_block_broadcast, std::move(b));
|
||||
|
||||
finish_query();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
141
validator/impl/accept-block.hpp
Normal file
141
validator/impl/accept-block.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "validator-set.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include "shard.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
/*
|
||||
*
|
||||
* block data (if not given) can be obtained from:
|
||||
* db as part of collated block
|
||||
* db as block
|
||||
* net
|
||||
* must write block data, block signatures and block state
|
||||
* initialize prev, before_split, after_merge
|
||||
* for masterchain write block proof and set next for prev block
|
||||
* for masterchain run new_block callback
|
||||
*
|
||||
*/
|
||||
|
||||
class AcceptBlockQuery : public td::actor::Actor {
|
||||
public:
|
||||
struct IsFake {};
|
||||
AcceptBlockQuery(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures, bool send_broadcast,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
|
||||
AcceptBlockQuery(IsFake fake, BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise);
|
||||
|
||||
private:
|
||||
static constexpr td::uint32 priority() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void written_block_data();
|
||||
void written_block_signatures();
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void written_block_info();
|
||||
void got_block_data(td::Ref<BlockData> data);
|
||||
void got_prev_state(td::Ref<ShardState> state);
|
||||
void written_state(td::Ref<ShardState> state);
|
||||
void written_block_proof();
|
||||
void got_last_mc_block(std::pair<td::Ref<MasterchainState>, BlockIdExt> last);
|
||||
void got_mc_state(Ref<ShardState> res);
|
||||
void find_known_ancestors();
|
||||
void require_proof_link(BlockIdExt id);
|
||||
void got_proof_link(BlockIdExt id, Ref<ProofLink> proof);
|
||||
bool create_top_shard_block_description();
|
||||
void create_topshard_blk_descr();
|
||||
void top_block_descr_validated(td::Result<Ref<ShardTopBlockDescription>> R);
|
||||
void written_block_next();
|
||||
void written_block_info_2();
|
||||
void applied();
|
||||
|
||||
private:
|
||||
BlockIdExt id_;
|
||||
Ref<BlockData> data_;
|
||||
std::vector<BlockIdExt> prev_;
|
||||
Ref<ValidatorSetQ> validator_set_;
|
||||
Ref<BlockSignatureSetQ> signatures_;
|
||||
bool is_fake_;
|
||||
bool send_broadcast_;
|
||||
bool ancestors_split_{false}, is_key_block_{false};
|
||||
td::Timestamp timeout_ = td::Timestamp::in(600.0);
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
FileHash signatures_hash_;
|
||||
BlockHandle handle_;
|
||||
Ref<Proof> proof_;
|
||||
Ref<ProofLink> proof_link_;
|
||||
|
||||
Ref<ShardState> state_;
|
||||
Ref<vm::Cell> block_root_;
|
||||
LogicalTime lt_;
|
||||
UnixTime created_at_;
|
||||
RootHash state_keep_old_hash_, state_old_hash_, state_hash_;
|
||||
BlockIdExt mc_blkid_, prev_mc_blkid_;
|
||||
|
||||
Ref<MasterchainStateQ> last_mc_state_;
|
||||
BlockIdExt last_mc_id_;
|
||||
std::vector<Ref<block::McShardHash>> ancestors_;
|
||||
BlockSeqno ancestors_seqno_;
|
||||
std::vector<Ref<ProofLink>> proof_links_;
|
||||
std::vector<Ref<vm::Cell>> proof_roots_;
|
||||
std::vector<BlockIdExt> link_prev_;
|
||||
Ref<vm::Cell> signatures_cell_;
|
||||
td::BufferSlice top_block_descr_data_;
|
||||
Ref<ShardTopBlockDescription> top_block_descr_;
|
||||
|
||||
td::PerfWarningTimer perf_timer_{"acceptblock", 0.1};
|
||||
|
||||
bool fatal_error(std::string msg, int code = -666);
|
||||
static bool check_send_error(td::actor::ActorId<AcceptBlockQuery> SelfId, td::Status error);
|
||||
template <typename T>
|
||||
static bool check_send_error(td::actor::ActorId<AcceptBlockQuery> SelfId, td::Result<T>& res) {
|
||||
return res.is_error() && check_send_error(std::move(SelfId), res.move_as_error());
|
||||
}
|
||||
bool create_new_proof();
|
||||
bool unpack_proof_link(BlockIdExt id, Ref<ProofLink> proof);
|
||||
|
||||
bool is_masterchain() const {
|
||||
return id_.id.is_masterchain();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
79
validator/impl/block.cpp
Normal file
79
validator/impl/block.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "block.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
using td::Ref;
|
||||
|
||||
BlockQ::BlockQ(const BlockQ& other) : data_(other.data_.clone()), id_(other.id_), root_(other.root_), boc_(other.boc_) {
|
||||
}
|
||||
|
||||
BlockQ::BlockQ(BlockIdExt id, td::BufferSlice data) : data_(std::move(data)), id_(id) {
|
||||
}
|
||||
|
||||
BlockQ::~BlockQ() {
|
||||
}
|
||||
|
||||
td::Status BlockQ::init() {
|
||||
if (root_.not_null()) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
if (data_.is_null()) {
|
||||
return td::Status::Error(-668, "cannot initialize a block from an empty BufferSlice");
|
||||
}
|
||||
vm::StaticBagOfCellsDbLazy::Options options;
|
||||
options.check_crc32c = true;
|
||||
auto res = vm::StaticBagOfCellsDbLazy::create(vm::BufferSliceBlobView::create(data_.clone()), options);
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
boc_ = res.move_as_ok();
|
||||
auto rc = boc_->get_root_count();
|
||||
if (rc.is_error()) {
|
||||
return rc.move_as_error();
|
||||
}
|
||||
if (rc.move_as_ok() != 1) {
|
||||
return td::Status::Error(-668, "shardchain block BoC is invalid");
|
||||
}
|
||||
auto res3 = boc_->get_root_cell(0);
|
||||
if (res3.is_error()) {
|
||||
return res3.move_as_error();
|
||||
}
|
||||
root_ = res3.move_as_ok();
|
||||
if (root_.is_null()) {
|
||||
return td::Status::Error(-668, "cannot extract root cell out of a shardchain block BoC");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockQ>> BlockQ::create(BlockIdExt id, td::BufferSlice data) {
|
||||
td::Ref<BlockQ> res{true, id, std::move(data)};
|
||||
auto err = res.unique_write().init();
|
||||
if (err.is_error()) {
|
||||
return err.move_as_error();
|
||||
} else {
|
||||
return std::move(res);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
62
validator/impl/block.hpp
Normal file
62
validator/impl/block.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "ton/ton-types.h"
|
||||
#include "interfaces/block.h"
|
||||
#include "vm/db/StaticBagOfCellsDb.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class BlockQ : public BlockData {
|
||||
private:
|
||||
td::BufferSlice data_;
|
||||
BlockIdExt id_;
|
||||
td::Ref<vm::Cell> root_;
|
||||
std::shared_ptr<vm::StaticBagOfCellsDb> boc_;
|
||||
//
|
||||
BlockQ(const BlockQ& other);
|
||||
td::Status init();
|
||||
|
||||
public:
|
||||
BlockQ(BlockIdExt id, td::BufferSlice data);
|
||||
BlockQ(BlockQ&& other) = default;
|
||||
~BlockQ() override;
|
||||
td::BufferSlice data() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
FileHash file_hash() const override {
|
||||
return id_.file_hash;
|
||||
}
|
||||
BlockIdExt block_id() const override {
|
||||
return id_;
|
||||
}
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
return root_;
|
||||
}
|
||||
BlockQ* make_copy() const override {
|
||||
return new BlockQ(*this);
|
||||
}
|
||||
static td::Result<td::Ref<BlockQ>> create(BlockIdExt id, td::BufferSlice data);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
478
validator/impl/check-proof.cpp
Normal file
478
validator/impl/check-proof.cpp
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "check-proof.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "fabric.h"
|
||||
#include "signature-set.hpp"
|
||||
#include "validator-set.hpp"
|
||||
#include "shard.hpp"
|
||||
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
|
||||
#include "validator/invariants.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
void CheckProof::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "timeout"));
|
||||
}
|
||||
|
||||
void CheckProof::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
VLOG(VALIDATOR_WARNING) << "aborting check proof for " << id_ << " query: " << reason;
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
bool CheckProof::fatal_error(td::Status error) {
|
||||
abort_query(std::move(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckProof::fatal_error(std::string err_msg, int err_code) {
|
||||
abort_query(td::Status::Error(err_code, err_msg));
|
||||
return false;
|
||||
}
|
||||
|
||||
void CheckProof::finish_query() {
|
||||
if (skip_check_signatures_) {
|
||||
// TODO: check other invariants
|
||||
} else if (is_proof()) {
|
||||
ValidatorInvariants::check_post_check_proof(handle_);
|
||||
} else {
|
||||
ValidatorInvariants::check_post_check_proof_link(handle_);
|
||||
}
|
||||
if (promise_) {
|
||||
VLOG(VALIDATOR_DEBUG) << "checked proof for " << handle_->id();
|
||||
promise_.set_result(handle_);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
bool CheckProof::check_send_error(td::actor::ActorId<CheckProof> SelfId, td::Status error) {
|
||||
if (error.is_error()) {
|
||||
td::actor::send_closure(std::move(SelfId), &CheckProof::abort_query, std::move(error));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckProof::init_parse(bool is_aux) {
|
||||
block::gen::BlockProof::Record proof;
|
||||
BlockIdExt proof_blk_id;
|
||||
if (!(tlb::unpack_cell(is_aux ? old_proof_root_ : proof_root_, proof) &&
|
||||
block::tlb::t_BlockIdExt.unpack(proof.proof_for.write(), proof_blk_id))) {
|
||||
return false;
|
||||
}
|
||||
BlockIdExt decl_id = (is_aux ? old_proof_ : proof_)->block_id();
|
||||
if (proof_blk_id != decl_id) {
|
||||
return fatal_error("block proof is for another block: declared "s + decl_id.to_str() + ", found " +
|
||||
proof_blk_id.to_str());
|
||||
}
|
||||
if (!is_aux) {
|
||||
if (proof_blk_id != id_) {
|
||||
return fatal_error("block proof is for another block: expected "s + id_.to_str() + ", found " +
|
||||
proof_blk_id.to_str());
|
||||
}
|
||||
if (!is_masterchain() && is_proof()) {
|
||||
return fatal_error("have a proof for non-masterchain block "s + id_.to_str());
|
||||
}
|
||||
} else {
|
||||
key_id_ = proof_blk_id;
|
||||
if (!is_masterchain()) {
|
||||
return fatal_error("cannot verify non-masterchain block "s + id_.to_str() +
|
||||
" using previous key masterchain block");
|
||||
}
|
||||
if (!key_id_.is_masterchain()) {
|
||||
return fatal_error("auxiliary key block "s + key_id_.to_str() + " does not belong to the masterchain");
|
||||
}
|
||||
if (key_id_.seqno() != prev_key_seqno_) {
|
||||
return fatal_error(
|
||||
PSTRING() << "cannot verify newer block " << id_.to_str() << " using key block " << key_id_.to_str()
|
||||
<< " because the newer block declares different previous key block seqno " << prev_key_seqno_);
|
||||
}
|
||||
if (key_id_.seqno() >= id_.seqno()) {
|
||||
return fatal_error("cannot verify block "s + id_.to_str() + " using key block " + key_id_.to_str() +
|
||||
" with larger or equal seqno");
|
||||
}
|
||||
}
|
||||
auto keep_cc_seqno = catchain_seqno_;
|
||||
auto keep_utime = created_at_;
|
||||
Ref<vm::Cell> sig_root = proof.signatures->prefetch_ref();
|
||||
if (sig_root.not_null()) {
|
||||
vm::CellSlice cs{vm::NoVmOrd(), sig_root};
|
||||
bool have_sig;
|
||||
if (!(cs.fetch_ulong(8) == 0x11 // block_signatures#11
|
||||
&& cs.fetch_uint_to(32, validator_hash_) // validator_set_hash:uint32
|
||||
&& cs.fetch_uint_to(32, catchain_seqno_) // catchain_seqno:uint32
|
||||
&& cs.fetch_uint_to(32, sig_count_) // sig_count:uint32
|
||||
&& cs.fetch_uint_to(64, sig_weight_) // sig_weight:uint64
|
||||
&& cs.fetch_bool_to(have_sig) && have_sig == (sig_count_ > 0) &&
|
||||
cs.size_ext() == ((unsigned)have_sig << 16))) {
|
||||
return fatal_error("cannot parse BlockSignatures");
|
||||
}
|
||||
sig_root_ = cs.prefetch_ref();
|
||||
if (!proof_blk_id.is_masterchain()) {
|
||||
return fatal_error("invalid ProofLink for non-masterchain block "s + proof_blk_id.to_str() +
|
||||
" with validator signatures present");
|
||||
}
|
||||
} else {
|
||||
validator_hash_ = 0;
|
||||
catchain_seqno_ = 0;
|
||||
sig_count_ = 0;
|
||||
sig_weight_ = 0;
|
||||
sig_root_.clear();
|
||||
}
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof.root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return fatal_error("block proof for block "s + proof_blk_id.to_str() +
|
||||
" does not contain a valid Merkle proof for the block header");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != proof_blk_id.root_hash) {
|
||||
return fatal_error("block proof for block "s + proof_blk_id.to_str() +
|
||||
" contains a Merkle proof with incorrect root hash: expected " +
|
||||
proof_blk_id.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::ExtBlkRef::Record mcref; // _ ExtBlkRef = BlkMasterInfo;
|
||||
ShardIdFull shard;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no &&
|
||||
block::gen::BlkPrevInfo{info.after_merge}.validate_ref(info.prev_ref) &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
(!info.not_master || tlb::unpack_cell(info.master_ref, mcref)))) {
|
||||
return fatal_error("cannot unpack block header in the Merkle proof");
|
||||
}
|
||||
BlockId blk_id{shard, (unsigned)info.seq_no};
|
||||
if (blk_id != proof_blk_id.id) {
|
||||
return fatal_error("block header in the Merkle proof corresponds to another block id: expected "s +
|
||||
proof_blk_id.id.to_str() + ", found " + blk_id.to_str());
|
||||
}
|
||||
if (info.not_master != !shard.is_masterchain()) {
|
||||
return fatal_error("block has invalid not_master flag in its (Merkelized) header");
|
||||
}
|
||||
vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update};
|
||||
if (!(upd_cs.is_special() && upd_cs.prefetch_long(8) == 4 // merkle update
|
||||
&& upd_cs.size_ext() == 0x20228)) {
|
||||
return fatal_error("invalid Merkle update in block");
|
||||
}
|
||||
state_old_hash_ = upd_cs.prefetch_ref(0)->get_hash(0).bits();
|
||||
state_hash_ = upd_cs.prefetch_ref(1)->get_hash(0).bits();
|
||||
lt_ = info.end_lt;
|
||||
created_at_ = info.gen_utime;
|
||||
after_merge_ = info.after_merge;
|
||||
before_split_ = info.before_split;
|
||||
// after_split_ = info.after_split;
|
||||
want_merge_ = info.want_merge;
|
||||
want_split_ = info.want_split;
|
||||
is_key_block_ = info.key_block;
|
||||
prev_key_seqno_ = info.prev_key_block_seqno;
|
||||
{
|
||||
auto res = block::unpack_block_prev_blk_ext(virt_root, proof_blk_id, prev_, mc_blkid_, after_split_);
|
||||
if (res.is_error()) {
|
||||
return fatal_error(res.message().str());
|
||||
}
|
||||
}
|
||||
CHECK(after_split_ == info.after_split);
|
||||
if (shard.is_masterchain() && (after_merge_ | before_split_ | after_split_)) {
|
||||
return fatal_error("block header declares split/merge for a masterchain block");
|
||||
}
|
||||
if (after_merge_ && after_split_) {
|
||||
return fatal_error("a block cannot be both after merge and after split at the same time");
|
||||
}
|
||||
int shard_pfx_len = ton::shard_prefix_length(shard.shard);
|
||||
if (after_split_ && !shard_pfx_len) {
|
||||
return fatal_error("a block with empty shard prefix cannot be after split");
|
||||
}
|
||||
if (after_merge_ && shard_pfx_len >= 60) {
|
||||
return fatal_error("a block split 60 times cannot be after merge");
|
||||
}
|
||||
if (is_key_block_ && !shard.is_masterchain()) {
|
||||
return fatal_error("a non-masterchain block cannot be a key block");
|
||||
}
|
||||
if (is_key_block_ && !is_aux) {
|
||||
// visit validator-set related fields in key blocks
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
mc_extra.key_block && mc_extra.config.not_null())) {
|
||||
return fatal_error("cannot unpack extra header of key masterchain block "s + blk_id.to_str());
|
||||
}
|
||||
auto cfg = block::Config::unpack_config(std::move(mc_extra.config));
|
||||
if (cfg.is_error()) {
|
||||
return fatal_error("cannot extract configuration from extra header of key masterchain block "s + blk_id.to_str() +
|
||||
" : " + cfg.move_as_error().to_string());
|
||||
}
|
||||
auto res = cfg.move_as_ok()->visit_validator_params();
|
||||
if (res.is_error()) {
|
||||
return fatal_error("cannot extract validator set configuration from extra header of key masterchain block "s +
|
||||
blk_id.to_str() + " : " + res.to_string());
|
||||
}
|
||||
}
|
||||
if (is_aux) {
|
||||
if (!is_key_block_) {
|
||||
return fatal_error("auxiliary proof passed for verification of the proof of block "s + id_.to_str() +
|
||||
" belongs to non-key block " + key_id_.to_str());
|
||||
}
|
||||
auto config_r = block::Config::extract_from_key_block(virt_root, block::Config::needValidatorSet);
|
||||
if (config_r.is_error()) {
|
||||
return fatal_error(config_r.move_as_error());
|
||||
}
|
||||
auto config = config_r.move_as_ok();
|
||||
if (!config) {
|
||||
return fatal_error("cannot extract configuration from previous key block " + key_id_.to_str());
|
||||
}
|
||||
ValidatorSetCompute vs_comp;
|
||||
auto res = vs_comp.init(config.get());
|
||||
if (res.is_error()) {
|
||||
return fatal_error(std::move(res));
|
||||
}
|
||||
vset_ = vs_comp.get_validator_set(id_.shard_full(), keep_utime, keep_cc_seqno);
|
||||
if (vset_.is_null()) {
|
||||
return fatal_error("cannot extract current validator set for block "s + id_.to_str() +
|
||||
" from previous key block " + key_id_.to_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckProof::start_up() {
|
||||
alarm_timestamp() = timeout_;
|
||||
|
||||
auto res = vm::std_boc_deserialize(proof_->data());
|
||||
if (res.is_error()) {
|
||||
abort_query(res.move_as_error());
|
||||
return;
|
||||
}
|
||||
proof_root_ = res.move_as_ok();
|
||||
|
||||
if (mode_ == m_relproof) {
|
||||
CHECK(old_proof_.not_null());
|
||||
res = vm::std_boc_deserialize(old_proof_->data());
|
||||
if (res.is_error()) {
|
||||
abort_query(res.move_as_error());
|
||||
return;
|
||||
}
|
||||
old_proof_root_ = res.move_as_ok();
|
||||
}
|
||||
|
||||
try {
|
||||
if (!init_parse()) {
|
||||
fatal_error("cannot parse proof for block "s + id_.to_str());
|
||||
return;
|
||||
}
|
||||
if (mode_ == m_relproof) {
|
||||
if (!init_parse(true)) {
|
||||
fatal_error("cannot parse proof of previous key block "s + key_id_.to_str());
|
||||
return;
|
||||
}
|
||||
if (!init_parse()) {
|
||||
fatal_error("cannot parse proof for block "s + id_.to_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (vm::VmError err) {
|
||||
fatal_error("error while processing Merkle proof: "s + err.get_msg());
|
||||
return;
|
||||
} catch (vm::VmVirtError err) {
|
||||
fatal_error("error while processing Merkle proof: "s + err.get_msg());
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, id_,
|
||||
true, [SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &CheckProof::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CheckProof::got_block_handle, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CheckProof::got_block_handle(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
CHECK(handle_);
|
||||
if (!is_proof() || skip_check_signatures_) {
|
||||
got_block_handle_2(handle_);
|
||||
return;
|
||||
}
|
||||
if (handle_->inited_proof()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
CHECK(is_proof() && prev_.size() == 1);
|
||||
if (mode_ == m_relproof) {
|
||||
CHECK(vset_.not_null());
|
||||
check_signatures(vset_);
|
||||
return;
|
||||
}
|
||||
if (mode_ == m_relstate) {
|
||||
process_masterchain_state();
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, prev_[0], priority(),
|
||||
timeout_, [SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &CheckProof::got_masterchain_state,
|
||||
td::Ref<MasterchainState>{R.move_as_ok()});
|
||||
});
|
||||
}
|
||||
|
||||
void CheckProof::got_masterchain_state(td::Ref<MasterchainState> state) {
|
||||
CHECK(is_proof());
|
||||
state_ = std::move(state);
|
||||
|
||||
if (state_->root_hash() != state_old_hash_) {
|
||||
fatal_error(PSTRING() << "invalid previous state hash in proof: expected " << state_->root_hash().to_hex()
|
||||
<< ", found in update " << state_old_hash_.to_hex());
|
||||
return;
|
||||
}
|
||||
vset_ = state_->get_validator_set(id_.shard_full());
|
||||
check_signatures(vset_);
|
||||
}
|
||||
|
||||
void CheckProof::process_masterchain_state() {
|
||||
CHECK(is_proof());
|
||||
CHECK(state_.not_null());
|
||||
|
||||
auto id = state_->get_block_id();
|
||||
if (!id.is_masterchain()) {
|
||||
fatal_error("cannot check a masterchain block proof starting from non-masterchain state for "s + id.to_str());
|
||||
return;
|
||||
}
|
||||
if (!is_masterchain()) {
|
||||
fatal_error("cannot check a non-masterchain block proof starting from masterchain state");
|
||||
return;
|
||||
}
|
||||
if (id.seqno() < prev_key_seqno_) {
|
||||
fatal_error(PSTRING() << "cannot check masterchain block proof for " << id_.to_str()
|
||||
<< " starting from masterchain state for " << id.to_str()
|
||||
<< " older than the previous key block with seqno " << prev_key_seqno_);
|
||||
return;
|
||||
}
|
||||
if (id.seqno() >= id_.seqno()) {
|
||||
fatal_error("cannot check masterchain block proof for "s + id_.to_str() +
|
||||
" starting from newer masterchain state for " + id.to_str());
|
||||
return;
|
||||
}
|
||||
auto state_q = Ref<MasterchainStateQ>(state_);
|
||||
CHECK(state_q.not_null());
|
||||
vset_ = state_q->get_validator_set(id_.shard_full(), created_at_, catchain_seqno_);
|
||||
check_signatures(vset_);
|
||||
}
|
||||
|
||||
void CheckProof::check_signatures(Ref<ValidatorSet> s) {
|
||||
if (s->get_catchain_seqno() != catchain_seqno_) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad validator catchain seqno: expected "
|
||||
<< s->get_catchain_seqno() << ", found "
|
||||
<< catchain_seqno_));
|
||||
return;
|
||||
}
|
||||
if (s->get_validator_set_hash() != validator_hash_) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad validator set hash: expected "
|
||||
<< s->get_validator_set_hash() << ", found "
|
||||
<< validator_hash_));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig_root_.is_null()) {
|
||||
fatal_error("no block signatures present in proof to check");
|
||||
return;
|
||||
}
|
||||
|
||||
auto sigs = BlockSignatureSetQ::fetch(sig_root_);
|
||||
if (sigs.is_null()) {
|
||||
fatal_error("cannot deserialize signature set");
|
||||
return;
|
||||
}
|
||||
if (sigs->signatures().size() != sig_count_) {
|
||||
fatal_error(PSTRING() << "signature count mismatch: present " << sigs->signatures().size() << ", declared "
|
||||
<< sig_count_);
|
||||
return;
|
||||
}
|
||||
|
||||
auto S = s->check_signatures(id_.root_hash, id_.file_hash, sigs);
|
||||
if (S.is_error()) {
|
||||
abort_query(S.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto s_weight = S.move_as_ok();
|
||||
if (s_weight != sig_weight_) {
|
||||
fatal_error(PSTRING() << "total signature weight mismatch: declared " << sig_weight_ << ", actual " << s_weight);
|
||||
return;
|
||||
}
|
||||
sig_ok_ = true;
|
||||
|
||||
if (handle_) {
|
||||
got_block_handle_2(handle_);
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, id_,
|
||||
true, [SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &CheckProof::got_block_handle_2, R.move_as_ok());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void CheckProof::got_block_handle_2(BlockHandle handle) {
|
||||
handle_ = std::move(handle);
|
||||
|
||||
handle_->set_split(before_split_);
|
||||
handle_->set_merge(after_merge_);
|
||||
handle_->set_is_key_block(is_key_block_);
|
||||
handle_->set_state_root_hash(state_hash_);
|
||||
handle_->set_logical_time(lt_);
|
||||
handle_->set_unix_time(created_at_);
|
||||
for (auto &prev : prev_) {
|
||||
handle_->set_prev(prev);
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) || td::actor::send_closure_bool(SelfId, &CheckProof::finish_query);
|
||||
});
|
||||
if (skip_check_signatures_) {
|
||||
// do not save proof if we skipped signatures
|
||||
handle_->flush(manager_, handle_, std::move(P));
|
||||
} else if (is_proof()) {
|
||||
auto proof = Ref<Proof>(proof_);
|
||||
CHECK(proof.not_null());
|
||||
CHECK(sig_ok_);
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::set_block_proof, handle_, std::move(proof),
|
||||
std::move(P));
|
||||
} else {
|
||||
CHECK(proof_.not_null());
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::set_block_proof_link, handle_, proof_, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
137
validator/impl/check-proof.hpp
Normal file
137
validator/impl/check-proof.hpp
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "interfaces/block-handle.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
/*
|
||||
*
|
||||
* check block proof
|
||||
* write proof
|
||||
* initialize prev, before_split, after_merge
|
||||
* initialize prev's next
|
||||
*
|
||||
*/
|
||||
|
||||
class CheckProof : public td::actor::Actor {
|
||||
public:
|
||||
CheckProof(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockHandle> promise, bool skip_check_signatures, td::Ref<ProofLink> prev_key_proof = {})
|
||||
: mode_(prev_key_proof.is_null() ? m_normal : m_relproof)
|
||||
, id_(id)
|
||||
, proof_(std::move(proof))
|
||||
, old_proof_(std::move(prev_key_proof))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise))
|
||||
, skip_check_signatures_(skip_check_signatures) {
|
||||
}
|
||||
CheckProof(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockHandle> promise, bool skip_check_signatures, td::Ref<MasterchainState> known_state)
|
||||
: mode_(m_relstate)
|
||||
, id_(id)
|
||||
, proof_(std::move(proof))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise))
|
||||
, state_(std::move(known_state))
|
||||
, skip_check_signatures_(skip_check_signatures) {
|
||||
}
|
||||
CheckProof(BlockIdExt id, td::Ref<ProofLink> proof_link, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise)
|
||||
: mode_(m_prooflink)
|
||||
, id_(id)
|
||||
, proof_(std::move(proof_link))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr td::uint32 priority() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
void got_block_handle(BlockHandle handle);
|
||||
void got_masterchain_state(td::Ref<MasterchainState> state);
|
||||
void process_masterchain_state();
|
||||
void check_signatures(Ref<ValidatorSet> vset);
|
||||
void got_block_handle_2(BlockHandle handle);
|
||||
|
||||
private:
|
||||
enum { m_normal, m_relproof, m_relstate, m_prooflink } mode_{m_normal};
|
||||
BlockIdExt id_, key_id_;
|
||||
td::Ref<ProofLink> proof_, old_proof_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<BlockHandle> promise_;
|
||||
|
||||
BlockHandle handle_;
|
||||
td::Ref<MasterchainState> state_;
|
||||
td::Ref<ValidatorSet> vset_;
|
||||
Ref<vm::Cell> proof_root_, sig_root_, old_proof_root_;
|
||||
|
||||
RootHash state_hash_, state_old_hash_;
|
||||
LogicalTime lt_;
|
||||
UnixTime created_at_;
|
||||
bool after_merge_, after_split_, before_split_, want_merge_, want_split_, is_key_block_;
|
||||
BlockIdExt mc_blkid_;
|
||||
std::vector<BlockIdExt> prev_;
|
||||
BlockSeqno prev_key_seqno_{~0U};
|
||||
CatchainSeqno catchain_seqno_{0};
|
||||
td::uint32 validator_hash_{0};
|
||||
td::uint32 sig_count_;
|
||||
ValidatorWeight sig_weight_;
|
||||
bool skip_check_signatures_{false};
|
||||
bool sig_ok_{false};
|
||||
|
||||
td::PerfWarningTimer perf_timer_{"checkproof", 0.1};
|
||||
|
||||
static bool check_send_error(td::actor::ActorId<CheckProof> SelfId, td::Status error);
|
||||
template <typename T>
|
||||
static bool check_send_error(td::actor::ActorId<CheckProof> SelfId, td::Result<T>& res) {
|
||||
return res.is_error() && check_send_error(std::move(SelfId), res.move_as_error());
|
||||
}
|
||||
bool fatal_error(std::string err_msg, int err_code = -666);
|
||||
bool fatal_error(td::Status error);
|
||||
bool init_parse(bool is_aux = false);
|
||||
bool is_proof() const {
|
||||
return mode_ != m_prooflink;
|
||||
}
|
||||
bool is_masterchain() const {
|
||||
return id_.is_masterchain();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
63
validator/impl/collate-query-impl.h
Normal file
63
validator/impl/collate-query-impl.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class CollateQuery : public td::actor::Actor {
|
||||
public:
|
||||
CollateQuery(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise);
|
||||
CollateQuery(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, ZeroStateIdExt zero_state_id,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise);
|
||||
|
||||
void alarm() override;
|
||||
|
||||
void abort_query(td::Status reason);
|
||||
void finish_query();
|
||||
|
||||
void start_up() override;
|
||||
void got_prev_state(td::Ref<MasterchainState> state);
|
||||
void written_block_data();
|
||||
void written_block_collated_data();
|
||||
|
||||
private:
|
||||
ShardIdFull shard_;
|
||||
UnixTime min_ts_;
|
||||
BlockIdExt min_masterchain_block_id_;
|
||||
std::vector<BlockIdExt> prev_;
|
||||
ZeroStateIdExt zero_state_id_;
|
||||
td::Ref<ValidatorSet> validator_set_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<BlockCandidate> promise_;
|
||||
|
||||
BlockCandidate candidate_;
|
||||
UnixTime ts_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
293
validator/impl/collator-impl.h
Normal file
293
validator/impl/collator-impl.h
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "shard.hpp"
|
||||
#include "top-shard-descr.hpp"
|
||||
#include "common/refcnt.hpp"
|
||||
#include "vm/cells.h"
|
||||
#include "vm/dict.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "block/block.h"
|
||||
#include "block/transaction.h"
|
||||
#include "block/block-db.h"
|
||||
#include "block/output-queue-merger.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "vm/cells/MerkleUpdate.h"
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class Collator final : public td::actor::Actor {
|
||||
using LtCellRef = block::LtCellRef;
|
||||
using NewOutMsg = block::NewOutMsg;
|
||||
const ShardIdFull shard;
|
||||
ton::BlockId new_id;
|
||||
bool busy{false};
|
||||
bool before_split_{false};
|
||||
bool after_split_{false};
|
||||
bool after_merge_{false};
|
||||
bool want_split_{false};
|
||||
bool want_merge_{false};
|
||||
bool right_child_{false};
|
||||
bool preinit_complete{false};
|
||||
bool is_key_block_{false};
|
||||
bool block_full_{false};
|
||||
bool inbound_queues_empty_{false};
|
||||
bool libraries_changed_{false};
|
||||
UnixTime min_ts;
|
||||
BlockIdExt min_mc_block_id;
|
||||
std::vector<BlockIdExt> prev_blocks;
|
||||
std::vector<Ref<ShardState>> prev_states;
|
||||
std::vector<Ref<BlockData>> prev_block_data;
|
||||
td::Bits256 created_by;
|
||||
Ref<ValidatorSet> validator_set;
|
||||
td::actor::ActorId<ValidatorManager> manager;
|
||||
td::Timestamp timeout;
|
||||
td::Promise<BlockCandidate> main_promise;
|
||||
ton::BlockSeqno last_block_seqno{0};
|
||||
ton::BlockSeqno prev_mc_block_seqno{0};
|
||||
ton::BlockSeqno new_block_seqno{0};
|
||||
ton::BlockSeqno prev_key_block_seqno_{0};
|
||||
int step{0};
|
||||
int pending{0};
|
||||
static constexpr int max_ihr_msg_size = 65535; // 64k
|
||||
static constexpr int max_ext_msg_size = 65535; // 64k
|
||||
static constexpr int max_blk_sign_size = 65535; // 64k
|
||||
static constexpr bool shard_splitting_enabled = true;
|
||||
|
||||
public:
|
||||
Collator(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
Ref<ValidatorSet> validator_set, td::Bits256 collator_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockCandidate> promise);
|
||||
~Collator() override = default;
|
||||
bool is_busy() const {
|
||||
return busy;
|
||||
}
|
||||
ShardId get_shard() const {
|
||||
return shard.shard;
|
||||
}
|
||||
WorkchainId workchain() const {
|
||||
return shard.workchain;
|
||||
}
|
||||
static constexpr td::uint32 priority() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
private:
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
int verbosity{3 * 0};
|
||||
int verify{1};
|
||||
ton::LogicalTime start_lt, max_lt;
|
||||
ton::UnixTime now_;
|
||||
ton::UnixTime prev_now_;
|
||||
ton::UnixTime now_upper_limit_{~0U};
|
||||
unsigned out_msg_queue_ops_{}, in_descr_cnt_{}, out_descr_cnt_{};
|
||||
Ref<MasterchainStateQ> mc_state_;
|
||||
Ref<BlockData> prev_mc_block;
|
||||
BlockIdExt mc_block_id_;
|
||||
Ref<vm::Cell> mc_state_root;
|
||||
Ref<vm::Cell> mc_block_root;
|
||||
td::BitArray<256> rand_seed_;
|
||||
std::unique_ptr<block::ConfigInfo> config_;
|
||||
std::unique_ptr<block::ShardConfig> shard_conf_;
|
||||
std::map<BlockSeqno, Ref<MasterchainStateQ>> aux_mc_states_;
|
||||
std::vector<block::McShardDescr> neighbors_;
|
||||
std::unique_ptr<block::OutputQueueMerger> nb_out_msgs_;
|
||||
std::vector<ton::StdSmcAddress> special_smcs;
|
||||
std::vector<std::pair<ton::StdSmcAddress, int>> ticktock_smcs;
|
||||
Ref<vm::Cell> prev_block_root;
|
||||
Ref<vm::Cell> prev_state_root_, prev_state_root_pure_;
|
||||
Ref<vm::Cell> state_root; // (new) shardchain state
|
||||
Ref<vm::Cell> state_update; // Merkle update from prev_state_root to state_root
|
||||
std::shared_ptr<vm::CellUsageTree> state_usage_tree_; // used to construct Merkle update
|
||||
Ref<vm::CellSlice> new_config_params_;
|
||||
ton::LogicalTime prev_state_lt_;
|
||||
ton::LogicalTime shards_max_end_lt_{0};
|
||||
ton::UnixTime prev_state_utime_;
|
||||
int global_id_{0};
|
||||
ton::BlockSeqno min_ref_mc_seqno_{~0U};
|
||||
ton::BlockIdExt prev_key_block_;
|
||||
ton::LogicalTime prev_key_block_lt_;
|
||||
bool accept_msgs_{true};
|
||||
bool shard_conf_adjusted_{false};
|
||||
td::uint64 overload_history_{0}, underload_history_{0};
|
||||
td::uint64 block_size_estimate_{};
|
||||
Ref<block::WorkchainInfo> wc_info_;
|
||||
std::vector<Ref<ShardTopBlockDescription>> shard_block_descr_;
|
||||
std::vector<Ref<ShardTopBlockDescrQ>> used_shard_block_descr_;
|
||||
std::unique_ptr<vm::Dictionary> shard_libraries_;
|
||||
Ref<vm::Cell> mc_state_extra;
|
||||
std::unique_ptr<vm::AugmentedDictionary> account_dict;
|
||||
std::map<ton::StdSmcAddress, std::unique_ptr<block::Account>> accounts;
|
||||
std::vector<block::StoragePrices> storage_prices_;
|
||||
block::StoragePhaseConfig storage_phase_cfg_{&storage_prices_};
|
||||
block::ComputePhaseConfig compute_phase_cfg_;
|
||||
block::ActionPhaseConfig action_phase_cfg_;
|
||||
td::RefInt256 masterchain_create_fee_, basechain_create_fee_;
|
||||
std::unique_ptr<block::BlockLimits> block_limits_;
|
||||
std::unique_ptr<block::BlockLimitStatus> block_limit_status_;
|
||||
ton::LogicalTime min_new_msg_lt{std::numeric_limits<td::uint64>::max()};
|
||||
block::CurrencyCollection total_balance_, old_total_balance_, total_validator_fees_;
|
||||
block::CurrencyCollection global_balance_, old_global_balance_, import_created_{0};
|
||||
Ref<vm::Cell> recover_create_msg_, mint_msg_;
|
||||
Ref<vm::Cell> new_block;
|
||||
block::ValueFlow value_flow_{block::ValueFlow::SetZero()};
|
||||
std::unique_ptr<vm::AugmentedDictionary> fees_import_dict_;
|
||||
std::map<ton::Bits256, int> ext_msg_map;
|
||||
std::vector<std::pair<Ref<vm::Cell>, ExtMessage::Hash>> ext_msg_list_;
|
||||
std::priority_queue<NewOutMsg, std::vector<NewOutMsg>, std::greater<NewOutMsg>> new_msgs;
|
||||
std::pair<ton::LogicalTime, ton::Bits256> last_proc_int_msg_, first_unproc_int_msg_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> in_msg_dict, out_msg_dict, out_msg_queue_, sibling_out_msg_queue_;
|
||||
std::unique_ptr<vm::Dictionary> ihr_pending;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> processed_upto_, sibling_processed_upto_;
|
||||
std::vector<ExtMessage::Hash> bad_ext_msgs_, delay_ext_msgs_;
|
||||
Ref<vm::Cell> shard_account_blocks_; // ShardAccountBlocks
|
||||
std::vector<Ref<vm::Cell>> collated_roots_;
|
||||
std::unique_ptr<ton::BlockCandidate> block_candidate;
|
||||
|
||||
td::PerfWarningTimer perf_timer_{"collate", 0.1};
|
||||
//
|
||||
block::Account* lookup_account(td::ConstBitPtr addr) const;
|
||||
std::unique_ptr<block::Account> make_account_from(td::ConstBitPtr addr, Ref<vm::CellSlice> account,
|
||||
Ref<vm::CellSlice> extra, bool force_create = false);
|
||||
td::Result<block::Account*> make_account(td::ConstBitPtr addr, bool force_create = false);
|
||||
td::actor::ActorId<Collator> get_self() {
|
||||
return actor_id(this);
|
||||
}
|
||||
bool init_utime();
|
||||
bool init_lt();
|
||||
bool fetch_config_params();
|
||||
bool fatal_error(td::Status error);
|
||||
bool fatal_error(int err_code, std::string err_msg);
|
||||
bool fatal_error(std::string err_msg, int err_code = -666);
|
||||
void check_pending();
|
||||
void after_get_mc_state(td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res);
|
||||
void after_get_shard_state(int idx, td::Result<Ref<ShardState>> res);
|
||||
void after_get_block_data(int idx, td::Result<Ref<BlockData>> res);
|
||||
void after_get_shard_blocks(td::Result<std::vector<Ref<ShardTopBlockDescription>>> res);
|
||||
bool preprocess_prev_mc_state();
|
||||
bool register_mc_state(Ref<MasterchainStateQ> other_mc_state);
|
||||
bool request_aux_mc_state(BlockSeqno seqno, Ref<MasterchainStateQ>& state);
|
||||
Ref<MasterchainStateQ> get_aux_mc_state(BlockSeqno seqno) const;
|
||||
void after_get_aux_shard_state(ton::BlockIdExt blkid, td::Result<Ref<ShardState>> res);
|
||||
bool fix_one_processed_upto(block::MsgProcessedUpto& proc, const ton::ShardIdFull& owner);
|
||||
bool fix_processed_upto(block::MsgProcessedUptoCollection& upto);
|
||||
void got_neighbor_out_queue(int i, td::Result<Ref<MessageQueue>> res);
|
||||
bool adjust_shard_config();
|
||||
bool store_shard_fees(ShardIdFull shard, const block::CurrencyCollection& fees,
|
||||
const block::CurrencyCollection& created);
|
||||
bool store_shard_fees(Ref<block::McShardHash> descr);
|
||||
bool import_new_shard_top_blocks();
|
||||
bool init_block_limits();
|
||||
bool compute_minted_amount(block::CurrencyCollection& to_mint);
|
||||
bool init_value_create();
|
||||
bool try_collate();
|
||||
bool do_preinit();
|
||||
bool do_collate();
|
||||
bool create_special_transactions();
|
||||
bool create_special_transaction(block::CurrencyCollection amount, Ref<vm::Cell> dest_addr_cell,
|
||||
Ref<vm::Cell>& in_msg);
|
||||
bool create_ticktock_transactions(int mask);
|
||||
bool create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, ton::LogicalTime req_start_lt, int mask);
|
||||
Ref<vm::Cell> create_ordinary_transaction(Ref<vm::Cell> msg_root);
|
||||
bool unpack_last_mc_state();
|
||||
bool unpack_last_state();
|
||||
bool unpack_merge_last_state();
|
||||
bool unpack_one_last_state(block::ShardState& ss, BlockIdExt blkid, Ref<vm::Cell> prev_state_root);
|
||||
bool split_last_state(block::ShardState& ss);
|
||||
bool import_shard_state_data(block::ShardState& ss);
|
||||
bool add_trivial_neighbor();
|
||||
bool add_trivial_neighbor_after_merge();
|
||||
bool out_msg_queue_cleanup();
|
||||
bool dequeue_message(Ref<vm::Cell> msg_envelope, ton::LogicalTime delivered_lt);
|
||||
bool check_prev_block(const BlockIdExt& listed, const BlockIdExt& prev, bool chk_chain_len = true);
|
||||
bool check_prev_block_exact(const BlockIdExt& listed, const BlockIdExt& prev);
|
||||
bool check_this_shard_mc_info();
|
||||
bool request_neighbor_msg_queues();
|
||||
void update_max_lt(ton::LogicalTime lt);
|
||||
bool is_masterchain() const {
|
||||
return shard.is_masterchain();
|
||||
}
|
||||
bool is_our_address(Ref<vm::CellSlice> addr_ref) const;
|
||||
bool is_our_address(ton::AccountIdPrefixFull addr_prefix) const;
|
||||
bool is_our_address(const ton::StdSmcAddress& addr) const;
|
||||
void after_get_external_messages(td::Result<std::vector<Ref<ExtMessage>>> res);
|
||||
td::Result<bool> register_external_message_cell(Ref<vm::Cell> ext_msg, const ExtMessage::Hash& ext_hash);
|
||||
// td::Result<bool> register_external_message(td::Slice ext_msg_boc);
|
||||
td::Result<bool> register_ihr_message_cell(Ref<vm::Cell> ihr_msg);
|
||||
td::Result<bool> register_ihr_message(td::Slice ihr_msg_boc);
|
||||
td::Result<bool> register_shard_signatures_cell(Ref<vm::Cell> shard_blk_signatures);
|
||||
td::Result<bool> register_shard_signatures(td::Slice shard_blk_signatures_boc);
|
||||
void register_new_msg(block::NewOutMsg msg);
|
||||
void register_new_msgs(block::Transaction& trans);
|
||||
bool process_new_messages(bool enqueue_only = false);
|
||||
int process_one_new_message(block::NewOutMsg msg, bool enqueue_only = false, Ref<vm::Cell>* is_special = nullptr);
|
||||
bool process_inbound_internal_messages();
|
||||
bool process_inbound_message(Ref<vm::CellSlice> msg, ton::LogicalTime lt, td::ConstBitPtr key,
|
||||
const block::McShardDescr& src_nb);
|
||||
bool process_inbound_external_messages();
|
||||
int process_external_message(Ref<vm::Cell> msg);
|
||||
bool enqueue_message(block::NewOutMsg msg, td::RefInt256 fwd_fees_remaining, ton::LogicalTime enqueued_lt);
|
||||
bool enqueue_transit_message(Ref<vm::Cell> msg, Ref<vm::Cell> old_msg_env, ton::AccountIdPrefixFull prev_prefix,
|
||||
ton::AccountIdPrefixFull cur_prefix, ton::AccountIdPrefixFull dest_prefix,
|
||||
td::RefInt256 fwd_fee_remaining, ton::LogicalTime enqueued_lt);
|
||||
bool delete_out_msg_queue_msg(td::ConstBitPtr key);
|
||||
bool insert_in_msg(Ref<vm::Cell> in_msg);
|
||||
bool insert_out_msg(Ref<vm::Cell> out_msg);
|
||||
bool register_out_msg_queue_op(bool force = false);
|
||||
bool update_min_mc_seqno(ton::BlockSeqno some_mc_seqno);
|
||||
bool combine_account_transactions();
|
||||
bool update_public_libraries();
|
||||
bool update_account_public_libraries(Ref<vm::Cell> orig_libs, Ref<vm::Cell> final_libs, const td::Bits256& addr);
|
||||
bool add_public_library(td::ConstBitPtr key, td::ConstBitPtr addr, Ref<vm::Cell> library);
|
||||
bool remove_public_library(td::ConstBitPtr key, td::ConstBitPtr addr);
|
||||
bool check_block_overload();
|
||||
bool create_mc_state_extra();
|
||||
bool create_shard_state();
|
||||
td::Result<Ref<vm::Cell>> get_config_data_from_smc(const ton::StdSmcAddress& cfg_addr);
|
||||
bool try_fetch_new_config(const ton::StdSmcAddress& cfg_addr, Ref<vm::Cell>& new_config);
|
||||
bool update_processed_upto();
|
||||
bool compute_out_msg_queue_info(Ref<vm::Cell>& out_msg_queue_info);
|
||||
bool compute_total_balance();
|
||||
bool store_master_ref(vm::CellBuilder& cb);
|
||||
bool store_prev_blk_ref(vm::CellBuilder& cb, bool after_merge);
|
||||
bool store_zero_state_ref(vm::CellBuilder& cb);
|
||||
bool create_block_info(Ref<vm::Cell>& block_info);
|
||||
bool check_value_flow();
|
||||
bool create_block_extra(Ref<vm::Cell>& block_extra);
|
||||
bool update_shard_config(const block::WorkchainSet& wc_set, const block::CatchainValidatorsConfig& ccvc,
|
||||
bool update_cc);
|
||||
bool create_mc_block_extra(Ref<vm::Cell>& mc_block_extra);
|
||||
bool create_block();
|
||||
Ref<vm::Cell> collate_shard_block_descr_set();
|
||||
bool create_collated_data();
|
||||
bool create_block_candidate();
|
||||
void return_block_candidate(td::Result<td::Unit> saved);
|
||||
bool update_last_proc_int_msg(const std::pair<ton::LogicalTime, ton::Bits256>& new_lt_hash);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
3800
validator/impl/collator.cpp
Normal file
3800
validator/impl/collator.cpp
Normal file
File diff suppressed because it is too large
Load diff
49
validator/impl/collator.h
Normal file
49
validator/impl/collator.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "validator/validator.h"
|
||||
#include "block/block-db.h"
|
||||
#include "vm/cells.h"
|
||||
|
||||
namespace ton {
|
||||
using td::Ref;
|
||||
|
||||
extern int collator_settings; // +1 = force want_split, +2 = force want_merge
|
||||
|
||||
class Collator : public td::actor::Actor {
|
||||
protected:
|
||||
Collator() = default;
|
||||
|
||||
public:
|
||||
virtual ~Collator() = default;
|
||||
static td::actor::ActorOwn<Collator> create_collator(
|
||||
td::actor::ActorId<block::BlockDb> block_db,
|
||||
ShardIdFull shard /* , td::actor::ActorId<ValidatorManager> validator_manager */);
|
||||
virtual void generate_block_candidate(ShardIdFull shard, td::Promise<BlockCandidate> promise) = 0;
|
||||
virtual td::Result<bool> register_external_message_cell(Ref<vm::Cell> ext_msg) = 0;
|
||||
virtual td::Result<bool> register_external_message(td::Slice ext_msg_boc) = 0;
|
||||
virtual td::Result<bool> register_ihr_message_cell(Ref<vm::Cell> ihr_msg) = 0;
|
||||
virtual td::Result<bool> register_ihr_message(td::Slice ihr_msg_boc) = 0;
|
||||
virtual td::Result<bool> register_shard_signatures_cell(Ref<vm::Cell> shard_blk_signatures) = 0;
|
||||
virtual td::Result<bool> register_shard_signatures(td::Slice shard_blk_signatures_boc) = 0;
|
||||
};
|
||||
|
||||
} // namespace ton
|
||||
74
validator/impl/external-message.cpp
Normal file
74
validator/impl/external-message.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "external-message.hpp"
|
||||
#include "vm/boc.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block-db.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
ExtMessageQ::ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull addr_prefix)
|
||||
: root_(std::move(root)), addr_prefix_(addr_prefix), data_(std::move(data)) {
|
||||
hash_ = block::compute_file_hash(data_);
|
||||
}
|
||||
|
||||
td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice data) {
|
||||
if (data.size() > max_ext_msg_size) {
|
||||
return td::Status::Error("external message too large, rejecting");
|
||||
}
|
||||
vm::BagOfCells boc;
|
||||
auto res = boc.deserialize(data.as_slice());
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
if (boc.get_root_count() != 1) {
|
||||
return td::Status::Error("external message is not a valid bag of cells"); // not a valid bag-of-Cells
|
||||
}
|
||||
auto ext_msg = boc.get_root_cell();
|
||||
if (ext_msg->get_level() != 0) {
|
||||
return td::Status::Error("external message must have zero level");
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd{}, ext_msg};
|
||||
if (cs.prefetch_ulong(2) != 2) { // ext_in_msg_info$10
|
||||
return td::Status::Error("external message must begin with ext_in_msg_info$10");
|
||||
}
|
||||
ton::Bits256 hash{ext_msg->get_hash().bits()};
|
||||
if (!block::gen::t_Message_Any.validate_ref(ext_msg)) {
|
||||
return td::Status::Error("external message is not a (Message Any) according to automated checks");
|
||||
}
|
||||
if (!block::tlb::t_Message.validate_ref(ext_msg)) {
|
||||
return td::Status::Error("external message is not a (Message Any) according to hand-written checks");
|
||||
}
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
if (!tlb::unpack_cell_inexact(ext_msg, info)) {
|
||||
return td::Status::Error("cannot unpack external message header");
|
||||
}
|
||||
auto dest_prefix = block::tlb::t_MsgAddressInt.get_prefix(info.dest);
|
||||
if (!dest_prefix.is_valid()) {
|
||||
return td::Status::Error("destination of an inbound external message is an invalid blockchain address");
|
||||
}
|
||||
return Ref<ExtMessageQ>{true, std::move(data), std::move(ext_msg), dest_prefix};
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
55
validator/impl/external-message.hpp
Normal file
55
validator/impl/external-message.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/external-message.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ExtMessageQ : public ExtMessage {
|
||||
td::Ref<vm::Cell> root_;
|
||||
AccountIdPrefixFull addr_prefix_;
|
||||
td::BufferSlice data_;
|
||||
Hash hash_;
|
||||
|
||||
public:
|
||||
static constexpr unsigned max_ext_msg_size = 65535;
|
||||
AccountIdPrefixFull shard() const override {
|
||||
return addr_prefix_;
|
||||
}
|
||||
td::BufferSlice serialize() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
return root_;
|
||||
}
|
||||
Hash hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull shard);
|
||||
static td::Result<td::Ref<ExtMessageQ>> create_ext_message(td::BufferSlice data);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
215
validator/impl/fabric.cpp
Normal file
215
validator/impl/fabric.cpp
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "fabric.h"
|
||||
#include "collator-impl.h"
|
||||
#include "validator/db/rootdb.hpp"
|
||||
#include "validator/block-handle.hpp"
|
||||
#include "apply-block.hpp"
|
||||
#include "accept-block.hpp"
|
||||
#include "shard.hpp"
|
||||
#include "block.hpp"
|
||||
#include "proof.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include "external-message.hpp"
|
||||
#include "ihr-message.hpp"
|
||||
#include "validate-query.hpp"
|
||||
#include "check-proof.hpp"
|
||||
#include "top-shard-descr.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "liteserver.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_) {
|
||||
return td::actor::create_actor<RootDb>("db", manager, db_root_);
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(BlockIdExt block_id, td::BufferSlice data) {
|
||||
auto res = BlockQ::create(block_id, std::move(data));
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
} else {
|
||||
return td::Ref<BlockData>{res.move_as_ok()};
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(ReceivedBlock data) {
|
||||
return create_block(data.id, std::move(data.data));
|
||||
}
|
||||
|
||||
td::Result<td::Ref<Proof>> create_proof(BlockIdExt masterchain_block_id, td::BufferSlice proof) {
|
||||
return Ref<ProofQ>{true, masterchain_block_id, std::move(proof)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ProofLink>> create_proof_link(BlockIdExt block_id, td::BufferSlice proof_link) {
|
||||
return Ref<ProofLinkQ>{true, block_id, std::move(proof_link)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockSignatureSet>> create_signature_set(td::BufferSlice sig_set) {
|
||||
return BlockSignatureSetQ::fetch(std::move(sig_set));
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> create_shard_state(BlockIdExt block_id, td::BufferSlice data) {
|
||||
auto res = ShardStateQ::fetch(block_id, std::move(data));
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
} else {
|
||||
return td::Ref<ShardState>{res.move_as_ok()};
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> create_shard_state(BlockIdExt block_id, td::Ref<vm::DataCell> root_cell) {
|
||||
auto res = ShardStateQ::fetch(block_id, {}, std::move(root_cell));
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
} else {
|
||||
return td::Ref<ShardState>{res.move_as_ok()};
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<BlockHandle> create_block_handle(td::BufferSlice data) {
|
||||
return ton::validator::BlockHandleImpl::create(std::move(data));
|
||||
}
|
||||
|
||||
BlockHandle create_empty_block_handle(BlockIdExt id) {
|
||||
return ton::validator::BlockHandleImpl::create_empty(id);
|
||||
}
|
||||
|
||||
td::Ref<BlockSignatureSet> create_signature_set(std::vector<BlockSignature> sig_set) {
|
||||
return td::Ref<BlockSignatureSetQ>{true, std::move(sig_set)};
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data) {
|
||||
TRY_RESULT(res, ExtMessageQ::create_ext_message(std::move(data)));
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
td::Result<td::Ref<IhrMessage>> create_ihr_message(td::BufferSlice data) {
|
||||
TRY_RESULT(res, IhrMessageQ::create_ihr_message(std::move(data)));
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
|
||||
td::Ref<BlockSignatureSet> approve_signatures, bool send_broadcast,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<AcceptBlockQuery>("accept", id, std::move(data), prev, std::move(validator_set),
|
||||
std::move(signatures), send_broadcast, manager, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<AcceptBlockQuery>("fakeaccept", AcceptBlockQuery::IsFake(), id, std::move(data),
|
||||
std::move(prev), std::move(validator_set), std::move(manager),
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<ApplyBlock>(PSTRING() << "apply " << id, id, std::move(block), manager, timeout,
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise, bool skip_check_signatures) {
|
||||
td::actor::create_actor<CheckProof>("checkproof", id, std::move(proof), manager, timeout, std::move(promise),
|
||||
skip_check_signatures)
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise,
|
||||
td::Ref<ProofLink> rel_key_block_proof, bool skip_check_signatures) {
|
||||
td::actor::create_actor<CheckProof>("checkproof/key", id, std::move(proof), manager, timeout, std::move(promise),
|
||||
skip_check_signatures, std::move(rel_key_block_proof))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise,
|
||||
td::Ref<MasterchainState> rel_mc_state, bool skip_check_signatures) {
|
||||
td::actor::create_actor<CheckProof>("checkproof/st", id, std::move(proof), manager, timeout, std::move(promise),
|
||||
skip_check_signatures, std::move(rel_mc_state))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockHandle> promise) {
|
||||
td::actor::create_actor<CheckProof>("checkprooflink", id, std::move(proof), manager, timeout, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<ValidateCandidateResult> promise, bool is_fake) {
|
||||
BlockSeqno seqno = 0;
|
||||
for (auto& p : prev) {
|
||||
if (p.seqno() > seqno) {
|
||||
seqno = p.seqno();
|
||||
}
|
||||
}
|
||||
td::actor::create_actor<ValidateQuery>(
|
||||
PSTRING() << (is_fake ? "fakevalidate" : "validateblock") << shard.to_str() << ":" << (seqno + 1), shard, min_ts,
|
||||
min_masterchain_block_id, std::move(prev), std::move(candidate), std::move(validator_set), std::move(manager),
|
||||
timeout, std::move(promise), is_fake)
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, PublicKeyHash collator_id, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
BlockSeqno seqno = 0;
|
||||
for (auto& p : prev) {
|
||||
if (p.seqno() > seqno) {
|
||||
seqno = p.seqno();
|
||||
}
|
||||
}
|
||||
td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, min_ts,
|
||||
min_masterchain_block_id, std::move(prev), std::move(validator_set),
|
||||
collator_id.bits256_value(), std::move(manager), timeout, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
LiteQuery::run_query(std::move(data), std::move(manager), std::move(promise));
|
||||
}
|
||||
|
||||
void run_validate_shard_block_description(td::BufferSlice data, BlockHandle masterchain_block,
|
||||
td::Ref<MasterchainState> masterchain_state,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardTopBlockDescription>> promise, bool is_fake) {
|
||||
auto id = masterchain_block->id();
|
||||
td::actor::create_actor<ValidateShardTopBlockDescr>("topshardfetch", std::move(data), id,
|
||||
std::move(masterchain_block), std::move(masterchain_state),
|
||||
manager, timeout, is_fake, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
132
validator/impl/ihr-message.cpp
Normal file
132
validator/impl/ihr-message.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "ihr-message.hpp"
|
||||
#include "vm/boc.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block-db.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
IhrMessageQ::IhrMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, BlockIdExt block,
|
||||
AccountIdPrefixFull addr_prefix)
|
||||
: root_(std::move(root)), addr_prefix_(addr_prefix), data_(std::move(data)), blkid_(block) {
|
||||
hash_ = block::compute_file_hash(data_);
|
||||
}
|
||||
|
||||
td::Result<Ref<IhrMessageQ>> IhrMessageQ::create_ihr_message(td::BufferSlice data) {
|
||||
if (data.size() > max_ihr_msg_size) {
|
||||
return td::Status::Error("IHR message too large, rejecting");
|
||||
}
|
||||
vm::BagOfCells boc;
|
||||
auto res = boc.deserialize(data.as_slice());
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
if (boc.get_root_count() != 3) {
|
||||
return td::Status::Error("IHR message is not a valid bag of cells with three roots"); // not a valid bag-of-Cells
|
||||
}
|
||||
auto ihr_msg = boc.get_root_cell(0), blk = boc.get_root_cell(1), proof = boc.get_root_cell(2);
|
||||
if (ihr_msg->get_level() != 0 || blk->get_level() != 0 || proof->get_level() != 0) {
|
||||
return td::Status::Error("IHR message must have zero level");
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd{}, ihr_msg};
|
||||
if (cs.prefetch_ulong(1) != 0) { // int_msg_info$0
|
||||
return td::Status::Error("IHR message must begin with int_msg_info$0");
|
||||
}
|
||||
ton::Bits256 hash{ihr_msg->get_hash().bits()};
|
||||
if (!block::gen::t_Message_Any.validate_ref(ihr_msg)) {
|
||||
return td::Status::Error("IHR message is not a (Message Any) according to automated checks");
|
||||
}
|
||||
if (!block::tlb::t_Message.validate_ref(ihr_msg)) {
|
||||
return td::Status::Error("IHR message is not a (Message Any) according to hand-written checks");
|
||||
}
|
||||
block::gen::CommonMsgInfo::Record_int_msg_info info;
|
||||
if (!tlb::unpack_cell_inexact(ihr_msg, info)) {
|
||||
return td::Status::Error("cannot unpack IHR message header");
|
||||
}
|
||||
auto dest_prefix = block::tlb::t_MsgAddressInt.get_prefix(info.dest);
|
||||
if (!dest_prefix.is_valid()) {
|
||||
return td::Status::Error("destination of an IHR message is an invalid blockchain address");
|
||||
}
|
||||
cs.load_ord(std::move(blk));
|
||||
BlockIdExt blkid;
|
||||
if (!(block::tlb::t_BlockIdExt.unpack(cs, blkid) && cs.empty_ext())) {
|
||||
return td::Status::Error("IHR message does not contain a valid source BlockIdExt");
|
||||
}
|
||||
try {
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error("IHR message does not contain a valid Merkle proof");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != blkid.root_hash) {
|
||||
return td::Status::Error("IHR message contains a Merkle proof with incorrect root hash: expected " +
|
||||
blkid.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
ShardIdFull shard;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no &&
|
||||
tlb::unpack_cell(blk.extra, extra))) {
|
||||
return td::Status::Error("cannot unpack block header in the Merkle proof of an IHR message");
|
||||
}
|
||||
if (blkid.shard_full() != shard || blkid.seqno() != BlockSeqno(info.seq_no)) {
|
||||
return td::Status::Error(
|
||||
"block header in the Merkle proof of an IHR message does not belong to the declared source block");
|
||||
}
|
||||
vm::AugmentedDictionary out_msg_dict{vm::load_cell_slice_ref(extra.out_msg_descr), 256,
|
||||
block::tlb::aug_OutMsgDescr};
|
||||
Bits256 key{ihr_msg->get_hash().bits()};
|
||||
auto descr = out_msg_dict.lookup(key);
|
||||
out_msg_dict.reset();
|
||||
if (descr.is_null()) {
|
||||
return td::Status::Error(
|
||||
"IHR message contains an invalid proof with OutMsgDescr not containing a key equal to the hash of the "
|
||||
"message");
|
||||
}
|
||||
if (descr->prefetch_ulong(3) != 1 || !descr->size_refs()) { // expect msg_export_new$001
|
||||
return td::Status::Error(
|
||||
"IHR message contains an invalid proof with OutMsg record not of type msg_export_new$001");
|
||||
}
|
||||
cs.load_ord(descr->prefetch_ref());
|
||||
if (!cs.size_refs()) {
|
||||
return td::Status::Error("IHR message contains an invalid MsgEnvelope");
|
||||
}
|
||||
if (key != cs.prefetch_ref()->get_hash().bits()) {
|
||||
return td::Status::Error(
|
||||
"IHR message contains an invalid proof with MsgEnvelope not pointing to the message included");
|
||||
}
|
||||
} catch (vm::VmError err) {
|
||||
return td::Status::Error("error while processing Merkle proof provided in IHR message: "s + err.get_msg());
|
||||
} catch (vm::VmVirtError err) {
|
||||
return td::Status::Error("error while processing Merkle proof provided in IHR message: "s + err.get_msg());
|
||||
}
|
||||
return Ref<IhrMessageQ>{true, std::move(data), std::move(ihr_msg), blkid, dest_prefix};
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
56
validator/impl/ihr-message.hpp
Normal file
56
validator/impl/ihr-message.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/ihr-message.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class IhrMessageQ : public IhrMessage {
|
||||
td::Ref<vm::Cell> root_;
|
||||
AccountIdPrefixFull addr_prefix_;
|
||||
td::BufferSlice data_;
|
||||
Hash hash_;
|
||||
BlockIdExt blkid_;
|
||||
|
||||
public:
|
||||
static constexpr unsigned max_ihr_msg_size = 65535;
|
||||
AccountIdPrefixFull shard() const override {
|
||||
return addr_prefix_;
|
||||
}
|
||||
td::BufferSlice serialize() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
return root_;
|
||||
}
|
||||
Hash hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
IhrMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, BlockIdExt block, AccountIdPrefixFull shard);
|
||||
static td::Result<td::Ref<IhrMessageQ>> create_ihr_message(td::BufferSlice data);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
1456
validator/impl/liteserver.cpp
Normal file
1456
validator/impl/liteserver.cpp
Normal file
File diff suppressed because it is too large
Load diff
139
validator/impl/liteserver.hpp
Normal file
139
validator/impl/liteserver.hpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "ton/ton-types.h"
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/Time.h"
|
||||
#include "interfaces/block-handle.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "interfaces/shard.h"
|
||||
#include "shard.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class LiteQuery : public td::actor::Actor {
|
||||
td::BufferSlice query_;
|
||||
td::actor::ActorId<ton::validator::ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::BufferSlice> promise_;
|
||||
int pending_{0};
|
||||
WorkchainId acc_workchain_;
|
||||
StdSmcAddress acc_addr_;
|
||||
LogicalTime trans_lt_;
|
||||
Bits256 trans_hash_;
|
||||
BlockIdExt base_blk_id_, blk_id_;
|
||||
Ref<MasterchainStateQ> mc_state_, mc_state0_;
|
||||
Ref<ShardStateQ> state_;
|
||||
Ref<BlockData> mc_block_, block_;
|
||||
std::function<void()> continuation_;
|
||||
bool cont_set_{false};
|
||||
td::BufferSlice shard_proof_;
|
||||
std::vector<Ref<vm::Cell>> roots_;
|
||||
std::vector<Ref<td::CntObject>> aux_objs_;
|
||||
std::vector<ton::BlockIdExt> blk_ids_;
|
||||
std::unique_ptr<block::BlkProofChain> chain_;
|
||||
|
||||
public:
|
||||
static constexpr double default_timeout_seconds = 4.5;
|
||||
LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
static void run_query(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
|
||||
private:
|
||||
bool fatal_error(td::Status error);
|
||||
bool fatal_error(std::string err_msg, int err_code = -400);
|
||||
bool fatal_error(int err_code, std::string err_msg = "");
|
||||
void abort_query(td::Status reason);
|
||||
bool finish_query(td::BufferSlice result);
|
||||
void alarm() override;
|
||||
void start_up() override;
|
||||
void perform_getTime();
|
||||
void perform_getVersion();
|
||||
void perform_getMasterchainInfo();
|
||||
void continue_getMasterchainInfo(Ref<MasterchainState> mc_state, BlockIdExt blkid);
|
||||
void perform_getBlock(BlockIdExt blkid);
|
||||
void continue_getBlock(BlockIdExt blkid, Ref<BlockData> block);
|
||||
void perform_getBlockHeader(BlockIdExt blkid, int mode);
|
||||
void continue_getBlockHeader(BlockIdExt blkid, int mode, Ref<BlockData> block);
|
||||
void perform_getState(BlockIdExt blkid);
|
||||
void continue_getState(BlockIdExt blkid, Ref<ShardState> state);
|
||||
void perform_sendMessage(td::BufferSlice ext_msg);
|
||||
void perform_getAccountState(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr);
|
||||
void continue_getAccountState_0(Ref<MasterchainState> mc_state, BlockIdExt blkid);
|
||||
void continue_getAccountState();
|
||||
void finish_getAccountState(td::BufferSlice shard_proof);
|
||||
void perform_getOneTransaction(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, LogicalTime lt);
|
||||
void continue_getOneTransaction();
|
||||
void perform_getTransactions(WorkchainId workchain, StdSmcAddress addr, LogicalTime lt, Bits256 hash, unsigned count);
|
||||
void continue_getTransactions(unsigned remaining, bool exact);
|
||||
void continue_getTransactions_2(BlockIdExt blkid, Ref<BlockData> block, unsigned remaining);
|
||||
void abort_getTransactions(td::Status error, ton::BlockIdExt blkid);
|
||||
void finish_getTransactions();
|
||||
void perform_getShardInfo(BlockIdExt blkid, ShardIdFull shard, bool exact);
|
||||
void perform_getAllShardsInfo(BlockIdExt blkid);
|
||||
void continue_getShardInfo(ShardIdFull shard, bool exact);
|
||||
void continue_getAllShardsInfo();
|
||||
void perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list = {});
|
||||
void continue_getConfigParams(int mode, std::vector<int> param_list);
|
||||
void perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, UnixTime utime);
|
||||
void perform_listBlockTransactions(BlockIdExt blkid, int mode, int count, Bits256 account, LogicalTime lt);
|
||||
void finish_listBlockTransactions(int mode, int count);
|
||||
void perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode);
|
||||
void continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, Ref<MasterchainStateQ> state);
|
||||
bool construct_proof_chain(ton::BlockIdExt id);
|
||||
bool construct_proof_link_forward(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool construct_proof_link_forward_cont(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool construct_proof_link_back_cont(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool finish_proof_chain(ton::BlockIdExt id);
|
||||
|
||||
bool request_block_data(BlockIdExt blkid);
|
||||
bool request_block_state(BlockIdExt blkid);
|
||||
bool request_block_data_state(BlockIdExt blkid);
|
||||
bool request_mc_block_data(BlockIdExt blkid);
|
||||
bool request_mc_block_state(BlockIdExt blkid);
|
||||
bool request_mc_block_data_state(BlockIdExt blkid);
|
||||
void got_block_state(BlockIdExt blkid, Ref<ShardState> state);
|
||||
void got_mc_block_state(BlockIdExt blkid, Ref<ShardState> state);
|
||||
void got_block_data(BlockIdExt blkid, Ref<BlockData> data);
|
||||
void got_mc_block_data(BlockIdExt blkid, Ref<BlockData> data);
|
||||
void dec_pending() {
|
||||
if (!--pending_) {
|
||||
check_pending();
|
||||
}
|
||||
}
|
||||
void check_pending();
|
||||
bool set_continuation(std::function<void()>&& cont);
|
||||
bool make_mc_state_root_proof(Ref<vm::Cell>& proof);
|
||||
bool make_state_root_proof(Ref<vm::Cell>& proof);
|
||||
bool make_state_root_proof(Ref<vm::Cell>& proof, Ref<ShardStateQ> state, Ref<BlockData> block,
|
||||
const BlockIdExt& blkid);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, vm::CellSlice& cs, ShardIdFull shard, ShardIdFull& true_shard,
|
||||
Ref<vm::Cell>& leaf, bool& found, bool exact = true);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, Ref<block::McShardHash>& info, ShardIdFull shard, bool exact = true);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, Ref<block::McShardHash>& info, AccountIdPrefixFull prefix);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, BlockIdExt& blkid, AccountIdPrefixFull prefix);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
30
validator/impl/message-queue.cpp
Normal file
30
validator/impl/message-queue.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "message-queue.hpp"
|
||||
|
||||
namespace ton {
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
MessageQueueQ* MessageQueueQ::make_copy() const {
|
||||
return new MessageQueueQ(*this);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
66
validator/impl/message-queue.hpp
Normal file
66
validator/impl/message-queue.hpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "interfaces/message-queue.h"
|
||||
|
||||
namespace ton {
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class ShardStateQ;
|
||||
|
||||
class MessageQueueQ : public MessageQueue {
|
||||
BlockIdExt blkid;
|
||||
RootHash rhash;
|
||||
Ref<vm::Cell> root;
|
||||
MessageQueueQ* make_copy() const override;
|
||||
|
||||
protected:
|
||||
friend class ShardStateQ;
|
||||
MessageQueueQ(const MessageQueueQ& other) = default;
|
||||
MessageQueueQ(MessageQueueQ&& other) = default;
|
||||
|
||||
public:
|
||||
MessageQueueQ(const BlockIdExt& _id, Ref<vm::Cell> _root) : blkid(_id), root(std::move(_root)) {
|
||||
if (root.is_null()) {
|
||||
rhash.set_zero();
|
||||
} else {
|
||||
rhash = root->get_hash().bits();
|
||||
}
|
||||
}
|
||||
virtual ~MessageQueueQ() = default;
|
||||
ShardIdFull get_shard() const override {
|
||||
return ShardIdFull(blkid);
|
||||
}
|
||||
BlockSeqno get_seqno() const override {
|
||||
return blkid.id.seqno;
|
||||
}
|
||||
BlockIdExt get_block_id() const override {
|
||||
return blkid;
|
||||
}
|
||||
RootHash root_hash() const override {
|
||||
return rhash;
|
||||
}
|
||||
td::Ref<vm::Cell> root_cell() const override {
|
||||
return root;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
143
validator/impl/proof.cpp
Normal file
143
validator/impl/proof.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "proof.hpp"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "validator-set.hpp"
|
||||
|
||||
namespace ton {
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
td::Result<Ref<ProofLink>> ProofQ::export_as_proof_link() const {
|
||||
TRY_RESULT(root, vm::std_boc_deserialize(data_));
|
||||
block::gen::BlockProof::Record proof;
|
||||
if (!(tlb::unpack_cell(std::move(root), proof))) {
|
||||
return td::Status::Error("cannot unpack BlockProof");
|
||||
}
|
||||
proof.signatures = vm::load_cell_slice_ref(vm::CellBuilder().store_long(0, 1).finalize());
|
||||
if (!(tlb::pack_cell(root, proof))) {
|
||||
return td::Status::Error("cannot pack new BlockProof");
|
||||
}
|
||||
TRY_RESULT(data, vm::std_boc_serialize(std::move(root)));
|
||||
return Ref<ProofLink>(td::make_ref<ProofLinkQ>(id_, std::move(data)));
|
||||
}
|
||||
|
||||
td::Result<BlockSeqno> ProofLinkQ::prev_key_mc_seqno() const {
|
||||
if (!id_.is_masterchain()) {
|
||||
return td::Status::Error(
|
||||
-668, "cannot compute previous key masterchain block from ProofLink of non-masterchain block "s + id_.to_str());
|
||||
}
|
||||
TRY_RESULT(pair, get_virtual_root(true));
|
||||
try {
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(std::move(pair.first), blk) && tlb::unpack_cell(blk.info, info) && !info.version)) {
|
||||
return td::Status::Error(-668,
|
||||
"cannot unpack block header in the Merkle proof for masterchain block "s + id_.to_str());
|
||||
}
|
||||
return info.prev_key_block_seqno;
|
||||
} catch (vm::VmVirtError &) {
|
||||
return td::Status::Error(-668, "virtualization error in masterchain block proof for "s + id_.to_str());
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ConfigHolder>> ProofLinkQ::get_key_block_config() const {
|
||||
if (!id_.is_masterchain()) {
|
||||
return td::Status::Error(
|
||||
-668, "cannot compute previous key masterchain block from ProofLink of non-masterchain block "s + id_.to_str());
|
||||
}
|
||||
TRY_RESULT(pair, get_virtual_root(true));
|
||||
try {
|
||||
TRY_RESULT(cfg, block::Config::extract_from_key_block(
|
||||
std::move(pair.first), block::Config::needValidatorSet | block::Config::needWorkchainInfo));
|
||||
return td::make_ref<ConfigHolderQ>(std::move(cfg), std::move(pair.second));
|
||||
} catch (vm::VmVirtError &) {
|
||||
return td::Status::Error(-668,
|
||||
"virtualization error while traversing masterchain block proof for "s + id_.to_str());
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> ProofLinkQ::get_virtual_root(
|
||||
bool lazy) const {
|
||||
if (data_.empty()) {
|
||||
return td::Status::Error(-668, "block proof is empty");
|
||||
}
|
||||
std::shared_ptr<vm::StaticBagOfCellsDb> boc;
|
||||
Ref<vm::Cell> root;
|
||||
if (lazy) {
|
||||
vm::StaticBagOfCellsDbLazy::Options options;
|
||||
options.check_crc32c = true;
|
||||
auto res = vm::StaticBagOfCellsDbLazy::create(vm::BufferSliceBlobView::create(data_.clone()), options);
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
boc = res.move_as_ok();
|
||||
TRY_RESULT(rc, boc->get_root_count());
|
||||
if (rc != 1) {
|
||||
return td::Status::Error(-668, "masterchain block proof BoC is invalid");
|
||||
}
|
||||
TRY_RESULT(t_root, boc->get_root_cell(0));
|
||||
root = std::move(t_root);
|
||||
} else {
|
||||
TRY_RESULT(t_root, vm::std_boc_deserialize(data_.as_slice()));
|
||||
root = std::move(t_root);
|
||||
}
|
||||
if (root.is_null()) {
|
||||
return td::Status::Error(-668, "cannot extract root cell out of a masterchain block proof BoC");
|
||||
}
|
||||
block::gen::BlockProof::Record proof;
|
||||
BlockIdExt proof_blk_id;
|
||||
if (!(tlb::unpack_cell(root, proof) && block::tlb::t_BlockIdExt.unpack(proof.proof_for.write(), proof_blk_id))) {
|
||||
return td::Status::Error(-668, "masterchain block proof is invalid");
|
||||
}
|
||||
if (proof_blk_id != id_) {
|
||||
return td::Status::Error(-668, "masterchain block proof is for another block");
|
||||
}
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof.root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error(-668, "block proof for block "s + proof_blk_id.to_str() +
|
||||
" does not contain a valid Merkle proof for the block header");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != proof_blk_id.root_hash) {
|
||||
return td::Status::Error(-668, "block proof for block "s + proof_blk_id.to_str() +
|
||||
" contains a Merkle proof with incorrect root hash: expected " +
|
||||
proof_blk_id.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
return std::make_pair(std::move(virt_root), std::move(boc));
|
||||
}
|
||||
|
||||
td::Ref<ValidatorSet> ConfigHolderQ::get_total_validator_set(int next) const {
|
||||
if (!config_) {
|
||||
LOG(ERROR) << "MasterchainStateQ::get_total_validator_set() : no config";
|
||||
return {};
|
||||
}
|
||||
auto nodes = config_->compute_total_validator_set(next);
|
||||
if (nodes.empty()) {
|
||||
return {};
|
||||
}
|
||||
return Ref<ValidatorSetQ>{true, 0, ton::ShardIdFull{}, std::move(nodes)};
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
94
validator/impl/proof.hpp
Normal file
94
validator/impl/proof.hpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "interfaces/proof.h"
|
||||
#include "interfaces/config.h"
|
||||
#include "block/block-db.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "vm/db/StaticBagOfCellsDb.h"
|
||||
|
||||
namespace ton {
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class ConfigHolderQ : public ConfigHolder {
|
||||
std::shared_ptr<block::Config> config_;
|
||||
std::shared_ptr<vm::StaticBagOfCellsDb> boc_;
|
||||
|
||||
public:
|
||||
ConfigHolderQ() = default;
|
||||
ConfigHolderQ(std::shared_ptr<block::Config> config, std::shared_ptr<vm::StaticBagOfCellsDb> boc)
|
||||
: config_(std::move(config)), boc_(std::move(boc)) {
|
||||
}
|
||||
ConfigHolderQ(std::shared_ptr<block::Config> config) : config_(std::move(config)) {
|
||||
}
|
||||
const block::Config *get_config() const {
|
||||
return config_.get();
|
||||
}
|
||||
ConfigHolderQ *make_copy() const override {
|
||||
return new ConfigHolderQ(*this);
|
||||
}
|
||||
// if necessary, add more public methods providing interface to config_->...()
|
||||
td::Ref<ValidatorSet> get_total_validator_set(int next) const override; // next = -1 -> prev, next = 0 -> cur
|
||||
};
|
||||
|
||||
class ProofLinkQ : virtual public ProofLink {
|
||||
protected:
|
||||
BlockIdExt id_;
|
||||
td::BufferSlice data_;
|
||||
|
||||
public:
|
||||
ProofLinkQ(const BlockIdExt &id, td::BufferSlice data) : id_(id), data_(std::move(data)) {
|
||||
}
|
||||
ProofLinkQ *make_copy() const override {
|
||||
return new ProofLinkQ(id_, data_.clone());
|
||||
}
|
||||
BlockIdExt block_id() const override {
|
||||
return id_;
|
||||
}
|
||||
td::BufferSlice data() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
td::Result<BlockSeqno> prev_key_mc_seqno() const override;
|
||||
td::Result<td::Ref<ConfigHolder>> get_key_block_config() const override;
|
||||
|
||||
protected:
|
||||
td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> get_virtual_root(
|
||||
bool lazy = false) const;
|
||||
};
|
||||
|
||||
#if TD_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4250) // Proof is an interface, so there is no problem here
|
||||
#endif
|
||||
class ProofQ : public Proof, public ProofLinkQ {
|
||||
public:
|
||||
ProofQ(BlockIdExt masterchain_block_id, td::BufferSlice data) : ProofLinkQ(masterchain_block_id, std::move(data)) {
|
||||
}
|
||||
ProofQ *make_copy() const override {
|
||||
return new ProofQ(id_, data_.clone());
|
||||
}
|
||||
td::Result<Ref<ProofLink>> export_as_proof_link() const override;
|
||||
};
|
||||
#if TD_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
534
validator/impl/shard.cpp
Normal file
534
validator/impl/shard.cpp
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "shard.hpp"
|
||||
#include "message-queue.hpp"
|
||||
#include "validator-set.hpp"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/db/BlobView.h"
|
||||
#include "vm/db/StaticBagOfCellsDb.h"
|
||||
#include "vm/cellslice.h"
|
||||
#include "vm/cells/MerkleUpdate.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
|
||||
#define LAZY_STATE_DESERIALIZE 1
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
ShardStateQ::ShardStateQ(const ShardStateQ& other)
|
||||
: blkid(other.blkid)
|
||||
, rhash(other.rhash)
|
||||
, data(other.data.is_null() ? td::BufferSlice{} : other.data.clone())
|
||||
, bocs_(other.bocs_)
|
||||
, root(other.root)
|
||||
, lt(other.lt)
|
||||
, utime(other.utime)
|
||||
, before_split_(other.before_split_)
|
||||
, fake_split_(other.fake_split_)
|
||||
, fake_merge_(other.fake_merge_) {
|
||||
}
|
||||
|
||||
ShardStateQ* ShardStateQ::make_copy() const {
|
||||
return new ShardStateQ(*this);
|
||||
}
|
||||
|
||||
ShardStateQ::ShardStateQ(const BlockIdExt& _id, td::BufferSlice _data) : blkid(_id), data(std::move(_data)) {
|
||||
}
|
||||
|
||||
ShardStateQ::ShardStateQ(const BlockIdExt& _id, Ref<vm::Cell> _root, td::BufferSlice _data)
|
||||
: blkid(_id), data(std::move(_data)), root(std::move(_root)) {
|
||||
}
|
||||
|
||||
td::Result<Ref<ShardStateQ>> ShardStateQ::fetch(const BlockIdExt& _id, td::BufferSlice _data, Ref<vm::Cell> _root) {
|
||||
if (_id.is_masterchain()) {
|
||||
auto res = MasterchainStateQ::fetch(_id, std::move(_data), std::move(_root));
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
} else {
|
||||
return Ref<ShardStateQ>{res.move_as_ok()};
|
||||
}
|
||||
}
|
||||
Ref<ShardStateQ> res{true, _id, std::move(_root), std::move(_data)};
|
||||
td::Status err = res.unique_write().init();
|
||||
if (err.is_error()) {
|
||||
return err;
|
||||
} else {
|
||||
return std::move(res);
|
||||
}
|
||||
}
|
||||
|
||||
td::Status ShardStateQ::init() {
|
||||
if (root.is_null()) {
|
||||
if (data.empty()) {
|
||||
return td::Status::Error(
|
||||
-668, "cannot initialize shardchain state without either a root cell or a BufferSlice with serialized data");
|
||||
}
|
||||
#if LAZY_STATE_DESERIALIZE
|
||||
vm::StaticBagOfCellsDbLazy::Options options;
|
||||
options.check_crc32c = true;
|
||||
auto res = vm::StaticBagOfCellsDbLazy::create(vm::BufferSliceBlobView::create(data.clone()), options);
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
auto boc = res.move_as_ok();
|
||||
auto rc = boc->get_root_count();
|
||||
if (rc.is_error()) {
|
||||
return rc.move_as_error();
|
||||
}
|
||||
if (rc.move_as_ok() != 1) {
|
||||
return td::Status::Error(-668, "shardchain state BoC is invalid");
|
||||
}
|
||||
auto res3 = boc->get_root_cell(0);
|
||||
bocs_.clear();
|
||||
bocs_.push_back(std::move(boc));
|
||||
#else
|
||||
auto res3 = vm::std_boc_deserialize(data.as_slice());
|
||||
#endif
|
||||
if (res3.is_error()) {
|
||||
return res3.move_as_error();
|
||||
}
|
||||
root = res3.move_as_ok();
|
||||
if (root.is_null()) {
|
||||
return td::Status::Error(-668, "cannot extract root cell out of a shardchain state BoC");
|
||||
}
|
||||
}
|
||||
rhash = root->get_hash().bits();
|
||||
block::gen::ShardStateUnsplit::Record info;
|
||||
if (!tlb::unpack_cell(root, info)) {
|
||||
return td::Status::Error(-668,
|
||||
"shardchain state for block "s + blkid.id.to_str() + " does not contain a valid header");
|
||||
}
|
||||
lt = info.gen_lt;
|
||||
utime = info.gen_utime;
|
||||
before_split_ = info.before_split;
|
||||
block::ShardId id{info.shard_id};
|
||||
ton::BlockId hdr_id{ton::ShardIdFull(id), info.seq_no};
|
||||
if (!id.is_valid() || get_shard() != ton::ShardIdFull(id) || get_seqno() != info.seq_no) {
|
||||
return td::Status::Error(-668, "header of unpacked shardchain state for block "s + blkid.id.to_str() +
|
||||
" contains BlockId " + hdr_id.to_str() +
|
||||
" different from the one originally required");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status ShardStateQ::validate_deep() const {
|
||||
if (data.empty()) {
|
||||
return td::Status::Error(-668,
|
||||
"cannot validate serialized shard state because no serialized shard state is present");
|
||||
}
|
||||
auto res = vm::std_boc_deserialize(data.as_slice());
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
auto root = res.move_as_ok();
|
||||
if (root.is_null()) {
|
||||
return td::Status::Error(-668, "cannot extract root cell out of a shardchain state BoC");
|
||||
}
|
||||
if (rhash != root->get_hash().bits()) {
|
||||
return td::Status::Error(-668, "root hash mismatch in a shardchain state BoC : expected "s + rhash.to_hex() +
|
||||
" , found " + root->get_hash().bits().to_hex(256));
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<Ref<MessageQueue>> ShardStateQ::message_queue() const {
|
||||
if (root.is_null()) {
|
||||
return {}; // GIGO
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd(), root};
|
||||
if (!cs.have(64, 1) || cs.prefetch_ulong(32) != (unsigned)block::tlb::ShardState::shard_state) {
|
||||
return td::Status::Error(-668, "state for block "s + blkid.id.to_str() + " is invalid");
|
||||
}
|
||||
if (fake_split_ || fake_merge_) {
|
||||
return td::Status::Error(-668, "cannot obtain message queue from a virtually split or merged state");
|
||||
}
|
||||
auto out_queue_info = cs.prefetch_ref();
|
||||
return Ref<MessageQueue>(Ref<MessageQueueQ>{true, blkid, std::move(out_queue_info)});
|
||||
}
|
||||
|
||||
td::Status ShardStateQ::apply_block(BlockIdExt newid, td::Ref<BlockData> block) {
|
||||
if (block.is_null()) {
|
||||
return td::Status::Error(-666, "the block to be applied to a previous state is absent");
|
||||
}
|
||||
Ref<vm::Cell> block_root = block->root_cell();
|
||||
if (root.is_null() || block_root.is_null()) {
|
||||
return td::Status::Error(-666, "cannot apply an (empty) block to an (empty) state");
|
||||
}
|
||||
if (newid != block->block_id()) {
|
||||
return td::Status::Error(-666, "block id mismatch in apply_block()");
|
||||
}
|
||||
RootHash blk_rhash{block_root->get_hash().bits()};
|
||||
if (blk_rhash != newid.root_hash) {
|
||||
return td::Status::Error(-666, "cannot apply a block because its root hash differs from expected");
|
||||
}
|
||||
if (before_split_ != fake_split_) {
|
||||
return td::Status::Error(
|
||||
-666, "cannot apply a block because previous state has before_split set, but it has not been split virtually");
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd{}, block_root};
|
||||
if (cs.prefetch_ulong(32) != 0x11ef55aa || !cs.have_refs(4)) {
|
||||
return td::Status::Error(-666, "invalid shardchain block header for block "s + block->block_id().id.to_str());
|
||||
}
|
||||
Ref<vm::Cell> update = cs.prefetch_ref(2); // Merkle update
|
||||
auto next_state_root = vm::MerkleUpdate::apply(root, update);
|
||||
if (next_state_root.is_null()) {
|
||||
return td::Status::Error("cannot apply Merkle update from block "s + block->block_id().id.to_str() +
|
||||
" to previous state");
|
||||
}
|
||||
blkid = block->block_id();
|
||||
// boc.reset(); // keep old lazy static bag of cells in case undeserialized branches are inherited by the current state
|
||||
data.clear();
|
||||
root = std::move(next_state_root);
|
||||
rhash = root->get_hash().bits();
|
||||
block::gen::ShardStateUnsplit::Record info;
|
||||
if (!tlb::unpack_cell(root, info)) {
|
||||
return td::Status::Error(
|
||||
-668, "newly-computed shardchain state for block "s + blkid.id.to_str() + " does not contain a valid header");
|
||||
}
|
||||
lt = info.gen_lt;
|
||||
utime = info.gen_utime;
|
||||
before_split_ = info.before_split;
|
||||
fake_split_ = fake_merge_ = false;
|
||||
block::ShardId id{info.shard_id};
|
||||
ton::BlockId hdr_id{ton::ShardIdFull(id), info.seq_no};
|
||||
if (!id.is_valid() || get_shard() != ton::ShardIdFull(id) || get_seqno() != info.seq_no) {
|
||||
return td::Status::Error(-668, "header of newly-computed shardchain state for block "s + blkid.id.to_str() +
|
||||
" contains a BlockId " + hdr_id.to_str() +
|
||||
" different from the one originally required");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<td::Ref<ShardState>> ShardStateQ::merge_with(const ShardState& with) const {
|
||||
const ShardStateQ& other = dynamic_cast<const ShardStateQ&>(with);
|
||||
if (fake_split_ || fake_merge_ || other.fake_split_ || other.fake_merge_) {
|
||||
return td::Status::Error(-666, "cannot merge blockchain states which have been split or merged immediately before");
|
||||
}
|
||||
if (before_split_ || other.before_split_) {
|
||||
return td::Status::Error(-666, "cannot merge blockchain states which have before_split flag set");
|
||||
}
|
||||
if (blkid.is_masterchain()) {
|
||||
return td::Status::Error(-666, "cannot merge masterchain states");
|
||||
}
|
||||
auto shard1 = blkid.shard_full(), shard2 = other.blkid.shard_full();
|
||||
if (shard1 == shard2 || !ton::shard_is_sibling(shard1, shard2)) {
|
||||
return td::Status::Error(-666, PSTRING() << "cannot merge states of shards " << shard1.to_str() << " and "
|
||||
<< shard2.to_str() << " that are not siblings");
|
||||
}
|
||||
Ref<vm::Cell> root, root1 = root_cell(), root2 = other.root_cell();
|
||||
if (shard1.shard > shard2.shard) {
|
||||
std::swap(root1, root2);
|
||||
}
|
||||
if (!block::gen::t_ShardState.cell_pack_split_state(root, std::move(root1), std::move(root2))) {
|
||||
return td::Status::Error(-667, "cannot construct a virtual split_state after a merge");
|
||||
}
|
||||
auto m = Ref<ShardStateQ>{
|
||||
true,
|
||||
ton::BlockIdExt{blkid.id.workchain, ton::shard_parent(blkid.id.shard),
|
||||
std::max(blkid.seqno(), other.blkid.seqno()), ton::Bits256::zero(), ton::Bits256::zero()},
|
||||
root};
|
||||
auto& ms = m.unique_write();
|
||||
ms.fake_merge_ = true;
|
||||
ms.rhash = root->get_hash().bits();
|
||||
ms.lt = std::max(lt, other.lt);
|
||||
ms.utime = std::max(utime, other.utime);
|
||||
ms.bocs_ = bocs_;
|
||||
ms.bocs_.insert(ms.bocs_.end(), other.bocs_.begin(), other.bocs_.end());
|
||||
return std::move(m);
|
||||
}
|
||||
|
||||
td::Result<std::pair<td::Ref<ShardState>, td::Ref<ShardState>>> ShardStateQ::split() const {
|
||||
if (fake_split_ || fake_merge_) {
|
||||
return td::Status::Error(-666, "cannot split blockchain state which has been split or merged immediately before");
|
||||
}
|
||||
if (!before_split_) {
|
||||
return td::Status::Error(-666, "cannot split blockchain state which does not have before_split flag set");
|
||||
}
|
||||
if (blkid.is_masterchain()) {
|
||||
return td::Status::Error(-666, "cannot split masterchain state");
|
||||
}
|
||||
auto l = Ref<ShardStateQ>{true, *this};
|
||||
auto r = Ref<ShardStateQ>{true, *this};
|
||||
auto& ls = l.unique_write();
|
||||
auto& rs = r.unique_write();
|
||||
ls.fake_split_ = rs.fake_split_ = true;
|
||||
ls.blkid.id.shard = ton::shard_child(blkid.id.shard, true);
|
||||
rs.blkid.id.shard = ton::shard_child(blkid.id.shard, false);
|
||||
return std::make_pair<Ref<ShardState>, Ref<ShardState>>(std::move(l), std::move(r));
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> ShardStateQ::serialize() const {
|
||||
td::PerfWarningTimer perf_timer_{"serializestate", 0.1};
|
||||
if (!data.is_null()) {
|
||||
return data.clone();
|
||||
}
|
||||
if (root.is_null()) {
|
||||
return td::Status::Error(-666, "cannot serialize an uninitialized state");
|
||||
}
|
||||
vm::BagOfCells new_boc;
|
||||
new_boc.set_root(root);
|
||||
auto res = new_boc.import_cells();
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
auto st_res = new_boc.serialize_to_slice(31);
|
||||
if (st_res.is_error()) {
|
||||
LOG(ERROR) << "cannot serialize a shardchain state";
|
||||
return st_res.move_as_error();
|
||||
}
|
||||
// data = st_res.move_as_ok();
|
||||
// return data.clone();
|
||||
return st_res.move_as_ok();
|
||||
}
|
||||
|
||||
MasterchainStateQ::MasterchainStateQ(const BlockIdExt& _id, td::BufferSlice _data)
|
||||
: MasterchainState(), ShardStateQ(_id, std::move(_data)) {
|
||||
}
|
||||
|
||||
MasterchainStateQ::MasterchainStateQ(const BlockIdExt& _id, Ref<vm::Cell> _root, td::BufferSlice _data)
|
||||
: MasterchainState(), ShardStateQ(_id, std::move(_root), std::move(_data)) {
|
||||
}
|
||||
|
||||
MasterchainStateQ* MasterchainStateQ::make_copy() const {
|
||||
return new MasterchainStateQ(*this);
|
||||
}
|
||||
|
||||
td::Result<Ref<MasterchainStateQ>> MasterchainStateQ::fetch(const BlockIdExt& _id, td::BufferSlice _data,
|
||||
Ref<vm::Cell> _root) {
|
||||
if (!ShardIdFull(_id).is_masterchain_ext()) {
|
||||
return td::Status::Error(-666,
|
||||
"invalid masterchain block/state id passed for creating a new masterchain state object");
|
||||
}
|
||||
Ref<MasterchainStateQ> res{true, _id, std::move(_root), std::move(_data)};
|
||||
td::Status err = res.unique_write().mc_init();
|
||||
if (err.is_error()) {
|
||||
return err;
|
||||
} else {
|
||||
return std::move(res);
|
||||
}
|
||||
}
|
||||
|
||||
td::Status MasterchainStateQ::mc_init() {
|
||||
auto err = init();
|
||||
if (err.is_error()) {
|
||||
return err;
|
||||
}
|
||||
return mc_reinit();
|
||||
}
|
||||
|
||||
td::Status MasterchainStateQ::mc_reinit() {
|
||||
auto res = block::ConfigInfo::extract_config(
|
||||
root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet |
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks);
|
||||
cur_validators_.reset();
|
||||
next_validators_.reset();
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
config_ = res.move_as_ok();
|
||||
CHECK(config_);
|
||||
CHECK(config_->set_block_id_ext(get_block_id()));
|
||||
|
||||
auto cv_root = config_->get_config_param(35, 34);
|
||||
if (cv_root.not_null()) {
|
||||
TRY_RESULT(validators, block::Config::unpack_validator_set(std::move(cv_root)));
|
||||
cur_validators_ = std::move(validators);
|
||||
}
|
||||
auto nv_root = config_->get_config_param(37, 36);
|
||||
if (nv_root.not_null()) {
|
||||
TRY_RESULT(validators, block::Config::unpack_validator_set(std::move(nv_root)));
|
||||
next_validators_ = std::move(validators);
|
||||
}
|
||||
|
||||
zerostate_id_ = config_->get_zerostate_id();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status MasterchainStateQ::apply_block(BlockIdExt id, td::Ref<BlockData> block) {
|
||||
auto err = ShardStateQ::apply_block(id, block);
|
||||
if (err.is_error()) {
|
||||
return err;
|
||||
}
|
||||
config_.reset();
|
||||
err = mc_reinit();
|
||||
if (err.is_error()) {
|
||||
LOG(ERROR) << "cannot extract masterchain-specific state data from newly-computed state for block "
|
||||
<< id.id.to_str() << " : " << err.to_string();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
td::Status MasterchainStateQ::prepare() {
|
||||
if (config_) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
return mc_reinit();
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> MasterchainStateQ::compute_validator_set(ShardIdFull shard, const block::ValidatorSet& vset,
|
||||
UnixTime time, CatchainSeqno ccseqno) const {
|
||||
if (!config_) {
|
||||
return {};
|
||||
}
|
||||
LOG(DEBUG) << "in compute_validator_set() for " << shard.to_str();
|
||||
auto nodes = config_->compute_validator_set_cc(shard, vset, time, &ccseqno);
|
||||
if (nodes.empty()) {
|
||||
return {};
|
||||
}
|
||||
return Ref<ValidatorSetQ>{true, ccseqno, shard, std::move(nodes)};
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> MasterchainStateQ::get_validator_set(ShardIdFull shard) const {
|
||||
if (!config_ || !cur_validators_) {
|
||||
LOG(ERROR) << "MasterchainStateQ::get_validator_set() : no config or no cur_validators";
|
||||
return {};
|
||||
}
|
||||
return compute_validator_set(shard, *cur_validators_, config_->utime, 0);
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> MasterchainStateQ::get_validator_set(ShardIdFull shard, UnixTime ts, CatchainSeqno cc_seqno) const {
|
||||
if (!config_ || !cur_validators_) {
|
||||
LOG(ERROR) << "MasterchainStateQ::get_validator_set() : no config or no cur_validators";
|
||||
return {};
|
||||
}
|
||||
auto nodes = config_->compute_validator_set(shard, *cur_validators_, ts, cc_seqno);
|
||||
if (nodes.empty()) {
|
||||
return {};
|
||||
}
|
||||
return Ref<ValidatorSetQ>{true, cc_seqno, shard, std::move(nodes)};
|
||||
}
|
||||
|
||||
// next = -1 -> prev, next = 0 -> cur
|
||||
Ref<ValidatorSet> MasterchainStateQ::get_total_validator_set(int next) const {
|
||||
if (!config_) {
|
||||
LOG(ERROR) << "MasterchainStateQ::get_total_validator_set() : no config";
|
||||
return {};
|
||||
}
|
||||
auto nodes = config_->compute_total_validator_set(next);
|
||||
if (nodes.empty()) {
|
||||
return {};
|
||||
}
|
||||
return Ref<ValidatorSetQ>{true, 0, ton::ShardIdFull{}, std::move(nodes)};
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> MasterchainStateQ::get_next_validator_set(ShardIdFull shard) const {
|
||||
if (!config_ || !cur_validators_) {
|
||||
LOG(ERROR) << "MasterchainStateQ::get_next_validator_set() : no config or no cur_validators";
|
||||
return {};
|
||||
}
|
||||
if (!next_validators_) {
|
||||
return compute_validator_set(shard, *cur_validators_, config_->utime, 1);
|
||||
}
|
||||
bool is_mc = shard.is_masterchain();
|
||||
auto ccv_cfg = config_->get_catchain_validators_config();
|
||||
unsigned cc_lifetime = is_mc ? ccv_cfg.mc_cc_lifetime : ccv_cfg.shard_cc_lifetime;
|
||||
if (next_validators_->utime_since > (config_->utime / cc_lifetime + 1) * cc_lifetime) {
|
||||
return compute_validator_set(shard, *cur_validators_, config_->utime, 1);
|
||||
} else {
|
||||
return compute_validator_set(shard, *next_validators_, config_->utime, 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Ref<McShardHash>> MasterchainStateQ::get_shards() const {
|
||||
if (!config_) {
|
||||
return {};
|
||||
}
|
||||
std::vector<ton::BlockId> shard_ids = config_->get_shard_hash_ids(true);
|
||||
std::vector<Ref<McShardHash>> v;
|
||||
for (const auto& b : shard_ids) {
|
||||
v.emplace_back(config_->get_shard_hash(ton::ShardIdFull(b)));
|
||||
CHECK(v.back().not_null());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
td::Ref<McShardHash> MasterchainStateQ::get_shard_from_config(ShardIdFull shard) const {
|
||||
if (!config_) {
|
||||
return {};
|
||||
}
|
||||
return config_->get_shard_hash(shard);
|
||||
}
|
||||
|
||||
bool MasterchainStateQ::rotated_all_shards() const {
|
||||
if (!config_) {
|
||||
return false;
|
||||
}
|
||||
return config_->rotated_all_shards();
|
||||
}
|
||||
|
||||
bool MasterchainStateQ::get_old_mc_block_id(ton::BlockSeqno seqno, ton::BlockIdExt& blkid,
|
||||
ton::LogicalTime* end_lt) const {
|
||||
return config_ && config_->get_old_mc_block_id(seqno, blkid, end_lt);
|
||||
}
|
||||
|
||||
bool MasterchainStateQ::check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict) const {
|
||||
return config_ && config_->check_old_mc_block_id(blkid, strict);
|
||||
}
|
||||
|
||||
td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
|
||||
if (!config_) {
|
||||
return 0;
|
||||
}
|
||||
auto wc_info = config_->get_workchain_info(workchain_id);
|
||||
return wc_info.not_null() ? wc_info->actual_min_split : 0;
|
||||
}
|
||||
|
||||
td::uint32 MasterchainStateQ::soft_min_split_depth(WorkchainId workchain_id) const {
|
||||
if (!config_) {
|
||||
return 0;
|
||||
}
|
||||
auto wc_info = config_->get_workchain_info(workchain_id);
|
||||
return wc_info.not_null() ? wc_info->min_split : 0;
|
||||
}
|
||||
|
||||
BlockSeqno MasterchainStateQ::min_ref_masterchain_seqno() const {
|
||||
return config_ ? config_->min_ref_mc_seqno_ : 0;
|
||||
}
|
||||
|
||||
BlockIdExt MasterchainStateQ::last_key_block_id() const {
|
||||
BlockIdExt block_id;
|
||||
LogicalTime lt = 0;
|
||||
if (config_) {
|
||||
config_->get_last_key_block(block_id, lt);
|
||||
}
|
||||
return block_id;
|
||||
}
|
||||
|
||||
BlockIdExt MasterchainStateQ::next_key_block_id(BlockSeqno seqno) const {
|
||||
BlockIdExt block_id;
|
||||
if (config_) {
|
||||
config_->get_next_key_block(seqno, block_id);
|
||||
}
|
||||
return block_id;
|
||||
}
|
||||
|
||||
BlockIdExt MasterchainStateQ::prev_key_block_id(BlockSeqno seqno) const {
|
||||
BlockIdExt block_id;
|
||||
if (config_) {
|
||||
config_->get_prev_key_block(seqno, block_id);
|
||||
}
|
||||
return block_id;
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
157
validator/impl/shard.hpp
Normal file
157
validator/impl/shard.hpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "interfaces/shard.h"
|
||||
#include "vm/db/StaticBagOfCellsDb.h"
|
||||
#include "block/mc-config.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class ShardStateQ : virtual public ShardState {
|
||||
protected:
|
||||
BlockIdExt blkid;
|
||||
|
||||
private:
|
||||
RootHash rhash;
|
||||
td::BufferSlice data;
|
||||
std::vector<std::shared_ptr<vm::StaticBagOfCellsDb>> bocs_;
|
||||
Ref<vm::Cell> root;
|
||||
LogicalTime lt{0};
|
||||
UnixTime utime{0};
|
||||
bool before_split_{false};
|
||||
bool fake_split_{false};
|
||||
bool fake_merge_{false};
|
||||
|
||||
protected:
|
||||
friend class Ref<ShardStateQ>;
|
||||
ShardStateQ(const ShardStateQ& other);
|
||||
ShardStateQ(ShardStateQ&& other) = default;
|
||||
|
||||
public:
|
||||
td::Status init();
|
||||
ShardStateQ(const BlockIdExt& _id, td::BufferSlice _data);
|
||||
ShardStateQ(const BlockIdExt& _id, Ref<vm::Cell> _root, td::BufferSlice _data = {});
|
||||
virtual ~ShardStateQ() = default;
|
||||
static td::Result<Ref<ShardStateQ>> fetch(const BlockIdExt& _id, td::BufferSlice _data, Ref<vm::Cell> _root = {});
|
||||
bool disable_boc() const override {
|
||||
return false;
|
||||
}
|
||||
ShardIdFull get_shard() const override {
|
||||
return ShardIdFull(blkid);
|
||||
}
|
||||
BlockSeqno get_seqno() const override {
|
||||
return blkid.id.seqno;
|
||||
}
|
||||
BlockIdExt get_block_id() const override {
|
||||
return blkid;
|
||||
}
|
||||
RootHash root_hash() const override {
|
||||
return rhash;
|
||||
}
|
||||
Ref<vm::Cell> root_cell() const override {
|
||||
return root;
|
||||
}
|
||||
bool before_split() const override {
|
||||
return before_split_;
|
||||
}
|
||||
UnixTime get_unix_time() const override {
|
||||
return utime;
|
||||
}
|
||||
LogicalTime get_logical_time() const override {
|
||||
return lt;
|
||||
}
|
||||
td::Status validate_deep() const override;
|
||||
ShardStateQ* make_copy() const override;
|
||||
td::Result<Ref<MessageQueue>> message_queue() const override;
|
||||
td::Status apply_block(BlockIdExt id, Ref<BlockData> block) override;
|
||||
td::Result<Ref<ShardState>> merge_with(const ShardState& with) const override;
|
||||
td::Result<std::pair<Ref<ShardState>, Ref<ShardState>>> split() const override;
|
||||
td::Result<td::BufferSlice> serialize() const override;
|
||||
};
|
||||
|
||||
#if TD_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4250) // MasterchainState is an interface, so there is no problem here
|
||||
#endif
|
||||
class MasterchainStateQ : public MasterchainState, public ShardStateQ {
|
||||
public:
|
||||
MasterchainStateQ(const BlockIdExt& _id, td::BufferSlice _data);
|
||||
MasterchainStateQ(const BlockIdExt& _id, Ref<vm::Cell> _root, td::BufferSlice _data = {});
|
||||
virtual ~MasterchainStateQ() = default;
|
||||
td::Status apply_block(BlockIdExt id, Ref<BlockData> block) override;
|
||||
Ref<ValidatorSet> get_validator_set(ShardIdFull shard) const override;
|
||||
Ref<ValidatorSet> get_next_validator_set(ShardIdFull shard) const override;
|
||||
Ref<ValidatorSet> get_total_validator_set(int next) const override; // next = -1 -> prev, next = 0 -> cur
|
||||
Ref<ValidatorSet> get_validator_set(ShardIdFull shard, UnixTime ts, CatchainSeqno cc_seqno) const;
|
||||
bool rotated_all_shards() const override;
|
||||
std::vector<Ref<McShardHash>> get_shards() const override;
|
||||
td::Ref<McShardHash> get_shard_from_config(ShardIdFull shard) const override;
|
||||
bool ancestor_is_valid(BlockIdExt id) const override {
|
||||
return check_old_mc_block_id(id);
|
||||
}
|
||||
bool workchain_is_active(WorkchainId workchain_id) const override {
|
||||
return has_workchain(workchain_id);
|
||||
}
|
||||
bool has_workchain(WorkchainId workchain) const {
|
||||
return config_ && config_->has_workchain(workchain);
|
||||
}
|
||||
td::uint32 min_split_depth(WorkchainId workchain_id) const override;
|
||||
td::uint32 soft_min_split_depth(WorkchainId workchain_id) const override;
|
||||
BlockSeqno min_ref_masterchain_seqno() const override;
|
||||
td::Status prepare() override;
|
||||
ZeroStateIdExt get_zerostate_id() const {
|
||||
return zerostate_id_;
|
||||
}
|
||||
ValidatorSessionConfig get_consensus_config() const override {
|
||||
return config_->get_consensus_config();
|
||||
}
|
||||
BlockIdExt last_key_block_id() const override;
|
||||
BlockIdExt next_key_block_id(BlockSeqno seqno) const override;
|
||||
BlockIdExt prev_key_block_id(BlockSeqno seqno) const override;
|
||||
MasterchainStateQ* make_copy() const override;
|
||||
|
||||
static td::Result<Ref<MasterchainStateQ>> fetch(const BlockIdExt& _id, td::BufferSlice _data,
|
||||
Ref<vm::Cell> _root = {});
|
||||
|
||||
bool get_old_mc_block_id(ton::BlockSeqno seqno, ton::BlockIdExt& blkid,
|
||||
ton::LogicalTime* end_lt = nullptr) const override;
|
||||
bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const override;
|
||||
std::shared_ptr<block::ConfigInfo> get_config() const {
|
||||
return config_;
|
||||
}
|
||||
|
||||
private:
|
||||
ZeroStateIdExt zerostate_id_;
|
||||
std::shared_ptr<block::ConfigInfo> config_;
|
||||
std::shared_ptr<block::ValidatorSet> cur_validators_, next_validators_;
|
||||
MasterchainStateQ(const MasterchainStateQ& other) = default;
|
||||
td::Status mc_init();
|
||||
td::Status mc_reinit();
|
||||
Ref<ValidatorSet> compute_validator_set(ShardIdFull shard, const block::ValidatorSet& vset, UnixTime time,
|
||||
CatchainSeqno cc_seqno) const;
|
||||
};
|
||||
#if TD_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace validator
|
||||
} // namespace ton
|
||||
118
validator/impl/signature-set.cpp
Normal file
118
validator/impl/signature-set.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "signature-set.hpp"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "vm/dict.h"
|
||||
#include "vm/boc.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
BlockSignatureSetQ *BlockSignatureSetQ::make_copy() const {
|
||||
std::vector<BlockSignature> vec;
|
||||
auto &sigs = signatures();
|
||||
for (auto &s : sigs) {
|
||||
vec.emplace_back(BlockSignature{s.node, s.signature.clone()});
|
||||
}
|
||||
return new BlockSignatureSetQ{std::move(vec)};
|
||||
}
|
||||
|
||||
td::BufferSlice BlockSignatureSetQ::serialize() const {
|
||||
if (!signatures().size()) {
|
||||
return {};
|
||||
}
|
||||
Ref<vm::Cell> root;
|
||||
CHECK(serialize_to(root));
|
||||
//std::cerr << "serializing BlockSignatureSet: ";
|
||||
//vm::CellSlice{vm::NoVm{}, root}.print_rec(std::cerr);
|
||||
//std::cerr << std::endl;
|
||||
auto res = vm::std_boc_serialize(std::move(root));
|
||||
LOG_CHECK(res.is_ok()) << res.move_as_error();
|
||||
return res.move_as_ok();
|
||||
}
|
||||
|
||||
bool BlockSignatureSetQ::serialize_to(Ref<vm::Cell> &ref) const {
|
||||
auto &sigs = signatures();
|
||||
vm::Dictionary dict{16}; // HashmapE 16 CryptoSignaturePair
|
||||
for (unsigned i = 0; i < sigs.size(); i++) {
|
||||
vm::CellBuilder cb;
|
||||
if (!(cb.store_bits_bool(sigs[i].node) // sig_pair$_ node_id_short:bits256
|
||||
&& cb.store_long_bool(5, 4) // ed25519_signature#5
|
||||
&& sigs[i].signature.size() == 64 // signature must be 64 bytes long
|
||||
&& cb.store_bytes_bool(sigs[i].signature.data(), 64) // R:bits256 s:bits256
|
||||
&& dict.set_builder(td::BitArray<16>{i}, cb, vm::Dictionary::SetMode::Add))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ref = std::move(dict).extract_root_cell();
|
||||
CHECK(sigs.size());
|
||||
CHECK(ref.not_null());
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<BlockSignatureSet> BlockSignatureSetQ::fetch(td::BufferSlice data) {
|
||||
if (!data.size()) {
|
||||
return Ref<BlockSignatureSetQ>{true, std::vector<BlockSignature>{}};
|
||||
}
|
||||
auto res = vm::std_boc_deserialize(std::move(data));
|
||||
if (res.is_error()) {
|
||||
return {};
|
||||
}
|
||||
return fetch(res.move_as_ok());
|
||||
}
|
||||
|
||||
Ref<BlockSignatureSet> BlockSignatureSetQ::fetch(Ref<vm::Cell> cell) {
|
||||
if (cell.is_null()) {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
std::vector<BlockSignature> vec;
|
||||
vm::Dictionary dict{std::move(cell), 16}; // HashmapE 16 CryptoSignaturePair
|
||||
unsigned i = 0;
|
||||
if (!dict.check_for_each([&](Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key, int n) -> bool {
|
||||
if (key.get_int(n) != i || cs_ref->size_ext() != 256 + 4 + 256 + 256) {
|
||||
return false;
|
||||
}
|
||||
vm::CellSlice cs{*cs_ref};
|
||||
NodeIdShort node_id;
|
||||
unsigned char signature[64];
|
||||
if (!(cs.fetch_bits_to(node_id) // sig_pair$_ node_id_short:bits256
|
||||
&& cs.fetch_ulong(4) == 5 // ed25519_signature#5
|
||||
&& cs.fetch_bytes(signature, 64) // R:bits256 s:bits256
|
||||
&& !cs.size_ext())) {
|
||||
return false;
|
||||
}
|
||||
vec.emplace_back(BlockSignature{node_id, td::BufferSlice{td::Slice{signature, 64}}});
|
||||
++i;
|
||||
return i <= max_signatures;
|
||||
})) {
|
||||
return {};
|
||||
}
|
||||
return Ref<BlockSignatureSetQ>{true, std::move(vec)};
|
||||
} catch (vm::VmError) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
45
validator/impl/signature-set.hpp
Normal file
45
validator/impl/signature-set.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "validator/interfaces/signature-set.h"
|
||||
#include "vm/cells.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class BlockSignatureSetQ : public BlockSignatureSet {
|
||||
enum { max_signatures = 1024 };
|
||||
|
||||
public:
|
||||
BlockSignatureSetQ(std::vector<BlockSignature> signatures) : BlockSignatureSet{std::move(signatures)} {
|
||||
}
|
||||
BlockSignatureSetQ* make_copy() const override;
|
||||
td::BufferSlice serialize() const override;
|
||||
bool serialize_to(Ref<vm::Cell>& ref) const;
|
||||
static Ref<BlockSignatureSet> fetch(td::BufferSlice data);
|
||||
static Ref<BlockSignatureSet> fetch(td::Ref<vm::Cell> cell);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
541
validator/impl/top-shard-descr.cpp
Normal file
541
validator/impl/top-shard-descr.cpp
Normal file
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "top-shard-descr.hpp"
|
||||
#include "common/errorcode.h"
|
||||
#include "shard.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include "validator-set.hpp"
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "vm/boc.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
ShardTopBlockDescrQ* ShardTopBlockDescrQ::make_copy() const {
|
||||
return new ShardTopBlockDescrQ{*this};
|
||||
}
|
||||
|
||||
td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cell> proof_root, bool is_head) {
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error(-666, std::string{} + "link for block " + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() +
|
||||
" does not contain a valid Merkle proof for the block header");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != cur_id.root_hash) {
|
||||
return td::Status::Error(-666, std::string{} + "link for block " + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() +
|
||||
" contains a Merkle proof with incorrect root hash: expected " +
|
||||
cur_id.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
bool after_split;
|
||||
BlockIdExt mc_blkid;
|
||||
auto res = block::unpack_block_prev_blk_try(virt_root, cur_id, link_prev_, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
return td::Status::Error(-666, std::string{"error in link for block "} + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() + ": " +
|
||||
res.move_as_error().to_string());
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::ValueFlow::Record flow;
|
||||
block::CurrencyCollection fees_collected, funds_created;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) && tlb::unpack_cell(blk.value_flow, flow) &&
|
||||
fees_collected.unpack(flow.fees_collected) && funds_created.unpack(flow.r2.created))) {
|
||||
return td::Status::Error(-666, std::string{"cannot unpack block header in link for block "} + cur_id.to_str());
|
||||
}
|
||||
CHECK(after_split == info.after_split);
|
||||
if (info.gen_catchain_seqno != catchain_seqno_) {
|
||||
return td::Status::Error(
|
||||
-666, PSTRING() << "link for block " << cur_id.to_str()
|
||||
<< " is invalid because block header has catchain_seqno = " << info.gen_catchain_seqno
|
||||
<< " while ShardTopBlockDescr declares " << catchain_seqno_);
|
||||
}
|
||||
if (info.gen_validator_list_hash_short != validator_set_hash_) {
|
||||
return td::Status::Error(-666, PSTRING() << "link for block " << cur_id.to_str()
|
||||
<< " is invalid because block header has validator_set_hash = "
|
||||
<< info.gen_validator_list_hash_short
|
||||
<< " while ShardTopBlockDescr declares " << validator_set_hash_);
|
||||
}
|
||||
if (chain_mc_blk_ids_.empty()) {
|
||||
after_split_ = info.after_split;
|
||||
after_merge_ = info.after_merge;
|
||||
before_split_ = info.before_split;
|
||||
gen_utime_ = first_gen_utime_ = info.gen_utime;
|
||||
} else {
|
||||
auto nx_mc_seqno = chain_mc_blk_ids_.back().id.seqno;
|
||||
if (nx_mc_seqno < mc_blkid.id.seqno) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"link for block "} + cur_id.to_str() + " refers to masterchain block " + mc_blkid.to_str() +
|
||||
" while the next block refers to an older masterchain block " + chain_mc_blk_ids_.back().to_str());
|
||||
} else if (nx_mc_seqno == mc_blkid.id.seqno && chain_mc_blk_ids_.back() != mc_blkid) {
|
||||
return td::Status::Error(-666, std::string{"link for block "} + cur_id.to_str() +
|
||||
" refers to masterchain block " + mc_blkid.to_str() +
|
||||
" while the next block refers to a different same height masterchain block " +
|
||||
chain_mc_blk_ids_.back().to_str());
|
||||
}
|
||||
if (info.before_split) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"intermediate link for block "} + cur_id.to_str() + " is declared to be before a split");
|
||||
}
|
||||
if (info.gen_utime > first_gen_utime_) {
|
||||
return td::Status::Error(-666, PSTRING() << "block creation unixtime goes back from " << info.gen_utime << " to "
|
||||
<< first_gen_utime_ << " in intermediate link for blocks "
|
||||
<< cur_id.to_str() << " and " << chain_blk_ids_.back().to_str());
|
||||
}
|
||||
first_gen_utime_ = info.gen_utime;
|
||||
}
|
||||
chain_mc_blk_ids_.push_back(mc_blkid);
|
||||
chain_blk_ids_.push_back(cur_id);
|
||||
chain_fees_.emplace_back(std::move(fees_collected), std::move(funds_created));
|
||||
if (!is_head) {
|
||||
if (info.after_split || info.after_merge) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"intermediate link for block "} + cur_id.to_str() + " is after a split or a merge");
|
||||
}
|
||||
CHECK(link_prev_.size() == 1);
|
||||
CHECK(link_prev_[0].id.shard == cur_id.id.shard);
|
||||
if (link_prev_[0].id.seqno + 1 != cur_id.id.seqno) {
|
||||
return td::Status::Error(-666, std::string{"intermediate link for block "} + cur_id.to_str() +
|
||||
" increases seqno by more than one from " + link_prev_[0].to_str());
|
||||
}
|
||||
cur_id = link_prev_[0];
|
||||
} else {
|
||||
hd_after_split_ = info.after_split;
|
||||
hd_after_merge_ = info.after_merge;
|
||||
CHECK(link_prev_.size() == 1U + info.after_merge);
|
||||
BlockSeqno sq = link_prev_[0].id.seqno;
|
||||
if (hd_after_merge_) {
|
||||
sq = std::max(sq, link_prev_[1].id.seqno);
|
||||
}
|
||||
if (sq + 1 != cur_id.id.seqno) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"initial link for block "} + cur_id.to_str() + " increases seqno by more than one from " +
|
||||
link_prev_[0].to_str() +
|
||||
(hd_after_merge_ ? std::string{" + "} + link_prev_[1].to_str() : std::string{""}));
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status ShardTopBlockDescrQ::unpack() {
|
||||
if (root_.is_null()) {
|
||||
if (data_.empty()) {
|
||||
return td::Status::Error(-666, "Shard top block description has no serialized data and no root cell");
|
||||
}
|
||||
auto res = vm::std_boc_deserialize(data_.clone());
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
root_ = res.move_as_ok();
|
||||
}
|
||||
block::gen::TopBlockDescr::Record rec;
|
||||
if (!(block::gen::t_TopBlockDescr.force_validate_ref(root_) && tlb::unpack_cell(root_, rec) &&
|
||||
block::tlb::t_BlockIdExt.unpack(rec.proof_for.write(), block_id_))) {
|
||||
std::cerr << "invalid ShardTopBlockDescr: ";
|
||||
block::gen::t_TopBlockDescr.print_ref(std::cerr, root_);
|
||||
vm::load_cell_slice(root_).print_rec(std::cerr);
|
||||
return td::Status::Error(-666, "Shard top block description is not a valid TopBlockDescr TL-B object");
|
||||
}
|
||||
LOG(DEBUG) << "unpacking a ShardTopBlockDescr for " << block_id_.to_str() << " with " << rec.len << " links";
|
||||
CHECK(rec.len > 0 && rec.len <= 8);
|
||||
// unpack signatures
|
||||
Ref<vm::Cell> sig_root = rec.signatures->prefetch_ref();
|
||||
if (sig_root.not_null()) {
|
||||
vm::CellSlice cs{vm::NoVmOrd(), sig_root};
|
||||
bool have_sig;
|
||||
if (!(cs.fetch_ulong(8) == 0x11 // block_signatures#11
|
||||
&& cs.fetch_uint_to(32, validator_set_hash_) // validator_set_hash:uint32
|
||||
&& cs.fetch_uint_to(32, catchain_seqno_) // catchain_seqno:uint32
|
||||
&& cs.fetch_uint_to(32, sig_count_) // sig_count:uint32
|
||||
&& cs.fetch_uint_to(64, sig_weight_) // sig_weight:uint64
|
||||
&& cs.fetch_bool_to(have_sig) && have_sig == (sig_count_ > 0) &&
|
||||
cs.size_ext() == ((unsigned)have_sig << 16))) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"cannot parse BlockSignatures in ShardTopBlockDescr for "} + block_id_.to_str());
|
||||
}
|
||||
sig_root_ = cs.prefetch_ref();
|
||||
sig_set_ = BlockSignatureSetQ::fetch(sig_root_);
|
||||
if (sig_set_.is_null() && sig_count_) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"cannot deserialize signature list in ShardTopBlockDescr for "} + block_id_.to_str());
|
||||
}
|
||||
} else {
|
||||
validator_set_hash_ = 0;
|
||||
catchain_seqno_ = 0;
|
||||
sig_count_ = 0;
|
||||
sig_weight_ = 0;
|
||||
sig_root_.clear();
|
||||
}
|
||||
if (!sig_count_ && !is_fake_) {
|
||||
return td::Status::Error(-666, std::string{"invalid BlockSignatures in ShardTopBlockDescr for "} +
|
||||
block_id_.to_str() + ": no signatures present, and fake mode is not enabled");
|
||||
}
|
||||
is_fake_ = !sig_count_;
|
||||
// unpack proof link chain
|
||||
auto chain = std::move(rec.chain);
|
||||
BlockIdExt cur_id = block_id_;
|
||||
for (int i = 0; i < rec.len; i++) {
|
||||
CHECK(chain->size_ext() == (i == rec.len - 1 ? 0x10000u : 0x20000u));
|
||||
auto proof = chain->prefetch_ref();
|
||||
proof_roots_.push_back(proof);
|
||||
if (i < rec.len - 1) {
|
||||
chain = vm::load_cell_slice_ref(chain->prefetch_ref(1));
|
||||
}
|
||||
try {
|
||||
auto res = unpack_one_proof(cur_id, std::move(proof), i == rec.len - 1);
|
||||
if (res.is_error()) {
|
||||
return res;
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return td::Status::Error("error unpacking proof link for "s + cur_id.to_str() + " in ShardTopBlockDescr for " +
|
||||
block_id_.to_str() + " : " + err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return td::Status::Error("virtualization error unpacking proof link for "s + cur_id.to_str() +
|
||||
" in ShardTopBlockDescr for " + block_id_.to_str() + " : " + err.get_msg());
|
||||
}
|
||||
}
|
||||
is_valid_ = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<Ref<ShardTopBlockDescrQ>> ShardTopBlockDescrQ::fetch(td::BufferSlice data, bool is_fake) {
|
||||
Ref<ShardTopBlockDescrQ> ref{true, std::move(data), is_fake};
|
||||
auto err = ref.unique_write().unpack();
|
||||
if (err.is_error()) {
|
||||
return err;
|
||||
} else {
|
||||
return std::move(ref);
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<Ref<ShardTopBlockDescrQ>> ShardTopBlockDescrQ::fetch(Ref<vm::Cell> root, bool is_fake) {
|
||||
Ref<ShardTopBlockDescrQ> ref{true, std::move(root), is_fake};
|
||||
auto err = ref.unique_write().unpack();
|
||||
if (err.is_error()) {
|
||||
return err;
|
||||
} else {
|
||||
return std::move(ref);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShardTopBlockDescrQ::may_be_valid(BlockHandle last_masterchain_block_handle,
|
||||
Ref<MasterchainState> last_masterchain_block_state) const {
|
||||
int res_flags = 0;
|
||||
return prevalidate(last_masterchain_block_handle->id(), std::move(last_masterchain_block_state),
|
||||
Mode::allow_next_vset, res_flags)
|
||||
.is_ok();
|
||||
}
|
||||
|
||||
td::Result<int> ShardTopBlockDescrQ::validate_internal(BlockIdExt last_mc_block_id, Ref<MasterchainState> last_mc_state,
|
||||
int& res_flags, int mode) const {
|
||||
if (!is_valid()) {
|
||||
return td::Status::Error(-666, "ShardTopBlockDescr is invalid or uninitialized");
|
||||
}
|
||||
CHECK(chain_blk_ids_.size() > 0 && chain_blk_ids_.size() <= 8);
|
||||
CHECK(chain_mc_blk_ids_.size() == chain_blk_ids_.size());
|
||||
Ref<MasterchainStateQ> state = Ref<MasterchainStateQ>(last_mc_state);
|
||||
if (state.is_null()) {
|
||||
return td::Status::Error(-666, "cannot validate ShardTopBlockDescr: no masterchain state given");
|
||||
}
|
||||
if (last_mc_block_id.id.seqno < chain_mc_blk_ids_[0].id.seqno) {
|
||||
BlockSeqno delta = chain_mc_blk_ids_[0].id.seqno - last_mc_block_id.id.seqno;
|
||||
// too new
|
||||
if ((mode & Mode::fail_new) || (delta > 8 && (mode & Mode::fail_too_new))) {
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is too new for us: it refers to masterchain block " +
|
||||
chain_mc_blk_ids_[0].id.to_str() + " but we know only " +
|
||||
last_mc_block_id.to_str());
|
||||
}
|
||||
return -1; // valid, but too new
|
||||
}
|
||||
auto config = state->get_config();
|
||||
BlockSeqno next_mc_seqno = ~BlockSeqno(0);
|
||||
for (const auto& mcid : chain_mc_blk_ids_) {
|
||||
if (mcid.id.seqno > next_mc_seqno) {
|
||||
res_flags |= 1; // permanently invalid
|
||||
return td::Status::Error(
|
||||
-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid because its chain refers to masterchain blocks with non-monotonic seqno");
|
||||
}
|
||||
next_mc_seqno = mcid.id.seqno;
|
||||
auto valid =
|
||||
(mcid.id.seqno == last_mc_block_id.id.seqno) ? (mcid == last_mc_block_id) : config->check_old_mc_block_id(mcid);
|
||||
if (!valid) {
|
||||
res_flags |= 1; // permanently invalid
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid because it refers to masterchain block " + mcid.to_str() +
|
||||
" which is not an ancestor of our block " + last_mc_block_id.to_str());
|
||||
}
|
||||
}
|
||||
auto oldl = config->get_shard_hash(ShardIdFull{block_id_.id.workchain, block_id_.id.shard - 1}, false);
|
||||
if (oldl.is_null()) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid or too new because this workchain is absent from known masterchain configuration");
|
||||
}
|
||||
if (oldl->seqno() >= block_id_.id.seqno) {
|
||||
// we know a shardchain block that it is at least as new as this one
|
||||
if (!(mode & allow_old)) {
|
||||
res_flags |= 1; // permanently invalidate unless old ShardTopBlockDescr are allowed
|
||||
}
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is too old: we already know a newer shardchain block " + oldl->blk_.to_str());
|
||||
}
|
||||
if (oldl->seqno() < link_prev_[0].id.seqno) {
|
||||
if (mode & Mode::fail_new) {
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is too new for us: it starts from shardchain block " +
|
||||
link_prev_[0].id.to_str() + " but we know only " + oldl->blk_.to_str());
|
||||
}
|
||||
return -1; // valid, but too new
|
||||
}
|
||||
auto oldr = oldl;
|
||||
if (ton::shard_is_proper_ancestor(shard(), oldl->shard())) {
|
||||
oldr = config->get_shard_hash(ShardIdFull{block_id_.id.workchain, block_id_.id.shard + 1}, false);
|
||||
if (oldr.is_null()) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid or too new because this workchain is absent from known masterchain configuration (?)");
|
||||
}
|
||||
if (oldr->seqno() >= block_id_.id.seqno) {
|
||||
// we know a shardchain block that it is at least as new as this one
|
||||
res_flags |= 1; // permanently invalidate unless old ShardTopBlockDescr are allowed
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid in a strange fashion: we already know a newer shardchain block " +
|
||||
oldr->blk_.to_str() +
|
||||
" but only in the right branch; corresponds to a shardchain fork?");
|
||||
}
|
||||
CHECK(ton::shard_is_proper_ancestor(shard(), oldr->shard()));
|
||||
CHECK(oldl->shard() < oldr->shard());
|
||||
} else {
|
||||
CHECK(ton::shard_is_ancestor(oldl->shard(), shard()));
|
||||
}
|
||||
if (oldr->seqno() < link_prev_.back().id.seqno) {
|
||||
if (mode & Mode::fail_new) {
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is too new for us: it starts from shardchain block " +
|
||||
link_prev_.back().id.to_str() + " but we know only " + oldr->blk_.to_str());
|
||||
}
|
||||
return -1; // valid, but too new
|
||||
}
|
||||
unsigned clen = block_id_.id.seqno - std::max(oldl->seqno(), oldr->seqno());
|
||||
CHECK(clen > 0 && clen <= 8);
|
||||
CHECK(clen <= size());
|
||||
if (clen < size()) {
|
||||
if (chain_blk_ids_[clen] != oldl->blk_) {
|
||||
res_flags |= 1;
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid: it contains a reference to its ancestor " +
|
||||
chain_blk_ids_[clen].to_str() +
|
||||
" but the masterchain refers to another shardchain block " +
|
||||
(oldl->seqno() < oldr->seqno() ? oldr->blk_.to_str() : oldl->blk_.to_str()) +
|
||||
" of the same height");
|
||||
}
|
||||
CHECK(oldl->shard() == shard());
|
||||
CHECK(oldl == oldr);
|
||||
} else {
|
||||
if (link_prev_[0] != oldl->blk_) {
|
||||
res_flags |= 1;
|
||||
return td::Status::Error(
|
||||
-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid: it contains a reference to its ancestor " + link_prev_[0].to_str() +
|
||||
" but the masterchain instead refers to another shardchain block " + oldl->blk_.to_str());
|
||||
}
|
||||
if (link_prev_.back() != oldr->blk_) {
|
||||
res_flags |= 1;
|
||||
return td::Status::Error(
|
||||
-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" is invalid: it contains a reference to its ancestor " + link_prev_.back().to_str() +
|
||||
" but the masterchain instead refers to another shardchain block " + oldr->blk_.to_str());
|
||||
}
|
||||
}
|
||||
LOG(DEBUG) << "ShardTopBlockDescr for " << block_id_.to_str() << " appears to have a valid chain of " << clen
|
||||
<< " new links out of " << size();
|
||||
// check validator_set_{ts,hash}
|
||||
int vset_ok = 0;
|
||||
auto vset = state->get_validator_set(shard());
|
||||
CHECK(vset.not_null());
|
||||
if (vset->get_catchain_seqno() == catchain_seqno_ && vset->get_validator_set_hash() == validator_set_hash_) {
|
||||
res_flags |= 4;
|
||||
vset_ok = 1;
|
||||
} else if (mode & allow_next_vset) {
|
||||
auto nvset = state->get_next_validator_set(shard());
|
||||
if (nvset->get_catchain_seqno() == catchain_seqno_ && nvset->get_validator_set_hash() == validator_set_hash_) {
|
||||
vset = std::move(nvset);
|
||||
res_flags |= 8;
|
||||
vset_ok = 2;
|
||||
}
|
||||
}
|
||||
if (!vset_ok) {
|
||||
res_flags |= 1;
|
||||
return td::Status::Error(-666, PSTRING()
|
||||
<< "ShardTopBlockDescr for " << block_id_.to_str()
|
||||
<< " is invalid because it refers to shard validator set with hash "
|
||||
<< validator_set_hash_ << " and catchain_seqno " << catchain_seqno_
|
||||
<< " while the current masterchain configuration expects "
|
||||
<< vset->get_validator_set_hash() << " and " << vset->get_catchain_seqno());
|
||||
}
|
||||
// check signatures
|
||||
if ((mode & skip_check_sig) || is_fake_ || sig_ok_) {
|
||||
return (int)clen;
|
||||
}
|
||||
if (sig_bad_) {
|
||||
return td::Status::Error(
|
||||
-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() + " does not have valid signatures");
|
||||
}
|
||||
CHECK(sig_set_.not_null());
|
||||
auto sig_chk = vset->check_signatures(block_id_.root_hash, block_id_.file_hash, sig_set_);
|
||||
if (sig_chk.is_error()) {
|
||||
res_flags |= 0x21;
|
||||
return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() +
|
||||
" does not have valid signatures: " + sig_chk.move_as_error().to_string());
|
||||
}
|
||||
res_flags |= 0x10; // signatures checked ok
|
||||
auto wt = sig_chk.move_as_ok();
|
||||
if (wt != sig_weight_) {
|
||||
res_flags |= 1;
|
||||
return td::Status::Error(-666, PSTRING() << "ShardTopBlockDescr for " << block_id_.to_str()
|
||||
<< " has incorrect signature weight " << sig_weight_
|
||||
<< " (actual weight is " << wt << ")");
|
||||
}
|
||||
LOG(DEBUG) << "ShardTopBlockDescr for " << block_id_.to_str() << " has valid validator signatures of total weight "
|
||||
<< sig_weight_ << " out of " << Ref<ValidatorSetQ>(vset)->get_total_weight();
|
||||
return (int)clen;
|
||||
}
|
||||
|
||||
td::Result<int> ShardTopBlockDescrQ::prevalidate(BlockIdExt last_mc_block_id, Ref<MasterchainState> last_mc_state,
|
||||
int mode, int& res_flags) const {
|
||||
res_flags = 0;
|
||||
auto res = validate_internal(last_mc_block_id, last_mc_state, res_flags, mode);
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Result<int> ShardTopBlockDescrQ::validate(BlockIdExt last_mc_block_id, Ref<MasterchainState> last_mc_state,
|
||||
int mode, int& res_flags) {
|
||||
res_flags = 0;
|
||||
auto res = validate_internal(last_mc_block_id, last_mc_state, res_flags, mode);
|
||||
if (res_flags & 1) {
|
||||
// permanently invalid
|
||||
is_valid_ = false;
|
||||
}
|
||||
if (res_flags & 0x10) {
|
||||
sig_ok_ = true;
|
||||
}
|
||||
if (res_flags & 0x20) {
|
||||
sig_bad_ = true;
|
||||
}
|
||||
if (res_flags & 4) {
|
||||
vset_cur_ = true;
|
||||
vset_next_ = false;
|
||||
} else if (res_flags & 8) {
|
||||
vset_cur_ = false;
|
||||
vset_next_ = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<BlockIdExt> ShardTopBlockDescrQ::get_prev_at(int pos) const {
|
||||
if (!is_valid() || pos < 0 || (unsigned)pos > size()) {
|
||||
return {};
|
||||
}
|
||||
if ((unsigned)pos < size()) {
|
||||
return {chain_blk_ids_.at(pos)};
|
||||
} else {
|
||||
return link_prev_;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<block::McShardHash> ShardTopBlockDescrQ::get_prev_descr(int pos, int sum_cnt) const {
|
||||
if (!is_valid() || pos < 0 || sum_cnt < 0 || (unsigned)pos >= size() || (unsigned)sum_cnt > size() ||
|
||||
(unsigned)(pos + sum_cnt) > size()) {
|
||||
return {};
|
||||
}
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_roots_.at(pos), 1);
|
||||
auto res = block::McShardHash::from_block(std::move(virt_root), chain_blk_ids_.at(pos).file_hash);
|
||||
if (res.not_null()) {
|
||||
auto& total_fees = res.write().fees_collected_;
|
||||
auto& funds_created = res.write().funds_created_;
|
||||
total_fees.set_zero();
|
||||
funds_created.set_zero();
|
||||
for (int i = 0; i < sum_cnt; i++) {
|
||||
total_fees += chain_fees_.at(pos + i).first;
|
||||
funds_created += chain_fees_[pos + i].second;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescr::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(descr_));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescr::abort_query(td::Status reason) {
|
||||
if (promise_) {
|
||||
promise_.set_error(std::move(reason));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
bool ValidateShardTopBlockDescr::fatal_error(td::Status error) {
|
||||
abort_query(std::move(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidateShardTopBlockDescr::fatal_error(std::string err_msg, int err_code) {
|
||||
return fatal_error(td::Status::Error(err_code, err_msg));
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescr::alarm() {
|
||||
abort_query(td::Status::Error(ErrorCode::timeout, "timeout in ValidateShardTopBlockDescr"));
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescr::start_up() {
|
||||
auto res = ShardTopBlockDescrQ::fetch(std::move(data_), is_fake_);
|
||||
if (res.is_error()) {
|
||||
abort_query(res.move_as_error());
|
||||
return;
|
||||
}
|
||||
descr_ = res.move_as_ok();
|
||||
CHECK(descr_->is_valid());
|
||||
int res_flags = 0;
|
||||
auto val_res = descr_.write().validate(mc_blkid_, state_, ShardTopBlockDescrQ::Mode::allow_next_vset, res_flags);
|
||||
if (val_res.is_error()) {
|
||||
abort_query(val_res.move_as_error());
|
||||
return;
|
||||
}
|
||||
CHECK(descr_->is_valid());
|
||||
finish_query();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
183
validator/impl/top-shard-descr.hpp
Normal file
183
validator/impl/top-shard-descr.hpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/shard-block.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "block/mc-config.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class ValidateShardTopBlockDescr;
|
||||
|
||||
class ShardTopBlockDescrQBase : public ShardTopBlockDescription {
|
||||
protected:
|
||||
td::BufferSlice data_;
|
||||
ShardTopBlockDescrQBase() = default;
|
||||
ShardTopBlockDescrQBase(const ShardTopBlockDescrQBase& other) : data_(other.data_.clone()) {
|
||||
}
|
||||
ShardTopBlockDescrQBase(ShardTopBlockDescrQBase&&) = default;
|
||||
ShardTopBlockDescrQBase(td::BufferSlice data) : data_(std::move(data)) {
|
||||
}
|
||||
};
|
||||
|
||||
class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase {
|
||||
public:
|
||||
enum Mode { fail_new = 1, fail_too_new = 2, allow_old = 4, allow_next_vset = 8, skip_check_sig = 16 };
|
||||
ShardIdFull shard() const override {
|
||||
return block_id_.shard_full();
|
||||
}
|
||||
BlockIdExt block_id() const override {
|
||||
return block_id_;
|
||||
}
|
||||
|
||||
bool may_be_valid(BlockHandle last_masterchain_block_handle,
|
||||
Ref<MasterchainState> last_masterchain_block_state) const override;
|
||||
td::Result<int> prevalidate(BlockIdExt last_mc_block_id, Ref<MasterchainState> last_mc_state, int mode,
|
||||
int& res_flags) const;
|
||||
td::Result<int> validate(BlockIdExt last_mc_block_id, Ref<MasterchainState> last_mc_state, int mode, int& res_flags);
|
||||
|
||||
td::BufferSlice serialize() const override {
|
||||
return data_.clone();
|
||||
}
|
||||
bool before_split() const override {
|
||||
return before_split_;
|
||||
}
|
||||
bool after_split() const override {
|
||||
return after_split_;
|
||||
}
|
||||
bool after_merge() const override {
|
||||
return after_merge_;
|
||||
}
|
||||
bool is_valid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
std::size_t size() const {
|
||||
return chain_blk_ids_.size();
|
||||
}
|
||||
UnixTime generated_at() const override {
|
||||
return gen_utime_;
|
||||
}
|
||||
CatchainSeqno catchain_seqno() const override {
|
||||
return catchain_seqno_;
|
||||
}
|
||||
std::vector<BlockIdExt> get_prev_at(int pos) const;
|
||||
Ref<block::McShardHash> get_prev_descr(int pos, int sum_cnt = 0) const;
|
||||
Ref<block::McShardHash> get_top_descr(int sum_cnt = 0) const {
|
||||
return get_prev_descr(0, sum_cnt);
|
||||
}
|
||||
Ref<vm::Cell> get_root() const {
|
||||
return root_;
|
||||
}
|
||||
ShardTopBlockDescrQ(td::BufferSlice data, bool is_fake = false)
|
||||
: ShardTopBlockDescrQBase(std::move(data)), is_fake_(is_fake) {
|
||||
}
|
||||
ShardTopBlockDescrQ(Ref<vm::Cell> root, bool is_fake = false)
|
||||
: ShardTopBlockDescrQBase(), root_(std::move(root)), is_fake_(is_fake) {
|
||||
}
|
||||
|
||||
ShardTopBlockDescrQ* make_copy() const override;
|
||||
|
||||
static td::Result<Ref<ShardTopBlockDescrQ>> fetch(td::BufferSlice data, bool is_fake = false);
|
||||
static td::Result<Ref<ShardTopBlockDescrQ>> fetch(Ref<vm::Cell> root, bool is_fake = false);
|
||||
|
||||
protected:
|
||||
friend class ValidateShardTopBlockDescr;
|
||||
td::Status unpack();
|
||||
|
||||
private:
|
||||
BlockIdExt block_id_;
|
||||
Ref<vm::Cell> root_;
|
||||
bool is_valid_{false};
|
||||
bool is_fake_{false};
|
||||
bool after_split_{false};
|
||||
bool after_merge_{false};
|
||||
bool before_split_{false};
|
||||
bool hd_after_split_{false};
|
||||
bool hd_after_merge_{false};
|
||||
bool sig_ok_{false};
|
||||
bool sig_bad_{false};
|
||||
bool vset_cur_{false};
|
||||
bool vset_next_{false};
|
||||
|
||||
UnixTime gen_utime_{0};
|
||||
CatchainSeqno catchain_seqno_{0};
|
||||
td::uint32 validator_set_hash_{0};
|
||||
td::uint32 sig_count_;
|
||||
ValidatorWeight sig_weight_;
|
||||
Ref<vm::Cell> sig_root_;
|
||||
Ref<BlockSignatureSet> sig_set_;
|
||||
std::vector<Ref<vm::Cell>> proof_roots_;
|
||||
std::vector<BlockIdExt> chain_blk_ids_;
|
||||
std::vector<BlockIdExt> chain_mc_blk_ids_;
|
||||
std::vector<BlockIdExt> link_prev_;
|
||||
std::vector<std::pair<block::CurrencyCollection, block::CurrencyCollection>> chain_fees_;
|
||||
UnixTime first_gen_utime_;
|
||||
|
||||
ShardTopBlockDescrQ(const ShardTopBlockDescrQ& other) = default;
|
||||
ShardTopBlockDescrQ(ShardTopBlockDescrQ&& other) = default;
|
||||
|
||||
td::Status unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cell> proof_root, bool is_head);
|
||||
td::Result<int> validate_internal(BlockIdExt last_mc_block_id, Ref<MasterchainState> last_mc_state, int& res_flags,
|
||||
int mode) const;
|
||||
};
|
||||
|
||||
class ValidateShardTopBlockDescr : public td::actor::Actor {
|
||||
public:
|
||||
ValidateShardTopBlockDescr(td::BufferSlice data, BlockIdExt masterchain_block, BlockHandle masterchain_handle,
|
||||
Ref<MasterchainState> masterchain_state, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, bool is_fake, td::Promise<Ref<ShardTopBlockDescription>> promise)
|
||||
: data_(std::move(data))
|
||||
, mc_blkid_(masterchain_block)
|
||||
, handle_(std::move(masterchain_handle))
|
||||
, state_(std::move(masterchain_state))
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, is_fake_(is_fake)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void finish_query();
|
||||
void abort_query(td::Status reason);
|
||||
bool fatal_error(td::Status error);
|
||||
bool fatal_error(std::string err_msg, int err_code = -666);
|
||||
void alarm() override;
|
||||
|
||||
void start_up() override;
|
||||
|
||||
private:
|
||||
td::BufferSlice data_;
|
||||
Ref<ShardTopBlockDescrQ> descr_;
|
||||
|
||||
BlockIdExt mc_blkid_;
|
||||
BlockHandle handle_;
|
||||
Ref<MasterchainState> state_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
bool is_fake_;
|
||||
td::Promise<Ref<ShardTopBlockDescription>> promise_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
5242
validator/impl/validate-query.cpp
Normal file
5242
validator/impl/validate-query.cpp
Normal file
File diff suppressed because it is too large
Load diff
352
validator/impl/validate-query.hpp
Normal file
352
validator/impl/validate-query.hpp
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "vm/cells.h"
|
||||
#include "vm/dict.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "block/transaction.h"
|
||||
#include "shard.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
class ErrorCtxAdd;
|
||||
class ErrorCtxSet;
|
||||
|
||||
struct ErrorCtx {
|
||||
protected:
|
||||
friend class ErrorCtxAdd;
|
||||
friend class ErrorCtxSet;
|
||||
std::vector<std::string> entries_;
|
||||
|
||||
public:
|
||||
ErrorCtx() = default;
|
||||
ErrorCtx(std::vector<std::string> str_list) : entries_(std::move(str_list)) {
|
||||
}
|
||||
ErrorCtx(std::string str) : entries_{str} {
|
||||
}
|
||||
std::string as_string() const;
|
||||
ErrorCtxAdd add_guard(std::string str_add);
|
||||
ErrorCtxSet set_guard(std::string str);
|
||||
ErrorCtxSet set_guard(std::vector<std::string> str_list);
|
||||
};
|
||||
|
||||
class ErrorCtxAdd {
|
||||
ErrorCtx& ctx_;
|
||||
|
||||
public:
|
||||
ErrorCtxAdd(ErrorCtx& ctx, std::string ctx_elem) : ctx_(ctx) {
|
||||
ctx_.entries_.push_back(std::move(ctx_elem));
|
||||
}
|
||||
~ErrorCtxAdd() {
|
||||
ctx_.entries_.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
class ErrorCtxSet {
|
||||
ErrorCtx& ctx_;
|
||||
std::vector<std::string> old_ctx_;
|
||||
|
||||
public:
|
||||
ErrorCtxSet(ErrorCtx& ctx, std::vector<std::string> new_ctx) : ctx_(ctx) {
|
||||
old_ctx_ = std::move(ctx_.entries_);
|
||||
ctx_.entries_ = std::move(new_ctx);
|
||||
}
|
||||
ErrorCtxSet(ErrorCtx& ctx, std::string new_ctx) : ErrorCtxSet(ctx, std::vector<std::string>{new_ctx}) {
|
||||
}
|
||||
~ErrorCtxSet() {
|
||||
ctx_.entries_ = std::move(old_ctx_);
|
||||
}
|
||||
};
|
||||
|
||||
inline ErrorCtxAdd ErrorCtx::add_guard(std::string str) {
|
||||
return ErrorCtxAdd(*this, std::move(str));
|
||||
}
|
||||
|
||||
inline ErrorCtxSet ErrorCtx::set_guard(std::string str) {
|
||||
return ErrorCtxSet(*this, std::move(str));
|
||||
}
|
||||
|
||||
inline ErrorCtxSet ErrorCtx::set_guard(std::vector<std::string> str_list) {
|
||||
return ErrorCtxSet(*this, std::move(str_list));
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* must write candidate to disk, if accepted
|
||||
* can reject block only if it is invalid (i.e. in case of
|
||||
* internal errors must retry or crash)
|
||||
* only exception: block can be rejected, if it is known from
|
||||
* masterchain, that it will not be part of shardchain finalized
|
||||
* state
|
||||
*
|
||||
*/
|
||||
|
||||
class ValidateQuery : public td::actor::Actor {
|
||||
public:
|
||||
ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
|
||||
|
||||
private:
|
||||
int verbosity{3 * 1};
|
||||
int pending{0};
|
||||
const ShardIdFull shard_;
|
||||
const BlockIdExt id_;
|
||||
UnixTime min_ts;
|
||||
BlockIdExt min_mc_block_id;
|
||||
std::vector<BlockIdExt> prev_blocks;
|
||||
std::vector<Ref<ShardState>> prev_states;
|
||||
BlockCandidate block_candidate;
|
||||
td::Ref<ValidatorSet> validator_set_;
|
||||
td::actor::ActorId<ValidatorManager> manager;
|
||||
td::Timestamp timeout;
|
||||
td::Promise<ValidateCandidateResult> main_promise;
|
||||
bool after_merge_{false};
|
||||
bool after_split_{false};
|
||||
bool before_split_{false};
|
||||
bool want_split_{false};
|
||||
bool want_merge_{false};
|
||||
bool is_key_block_{false};
|
||||
bool update_shard_cc_{false};
|
||||
bool is_fake_{false};
|
||||
BlockSeqno prev_key_seqno_{~0u};
|
||||
int stage_{0};
|
||||
td::BitArray<64> shard_pfx_;
|
||||
int shard_pfx_len_;
|
||||
|
||||
Ref<vm::Cell> prev_state_root_;
|
||||
Ref<vm::Cell> state_root_;
|
||||
Ref<vm::Cell> state_update_;
|
||||
ton::Bits256 prev_state_hash_, state_hash_;
|
||||
|
||||
ErrorCtx error_ctx_;
|
||||
|
||||
td::Ref<MasterchainStateQ> mc_state_, latest_mc_state_;
|
||||
td::Ref<vm::Cell> mc_state_root_;
|
||||
BlockIdExt mc_blkid_, latest_mc_blkid_;
|
||||
ton::BlockSeqno mc_seqno_{0}, latest_mc_seqno_;
|
||||
|
||||
Ref<vm::Cell> block_root_;
|
||||
std::vector<Ref<vm::Cell>> collated_roots_;
|
||||
std::map<RootHash, Ref<vm::Cell>> virt_roots_;
|
||||
std::unique_ptr<vm::Dictionary> top_shard_descr_dict_;
|
||||
|
||||
Ref<vm::CellSlice> shard_hashes_; // from McBlockExtra
|
||||
Ref<vm::CellSlice> blk_config_params_; // from McBlockExtra
|
||||
Ref<BlockSignatureSet> prev_signatures_; // from McBlockExtra (UNCHECKED)
|
||||
Ref<vm::Cell> recover_create_msg_, mint_msg_; // from McBlockExtra (UNCHECKED)
|
||||
|
||||
std::unique_ptr<block::ConfigInfo> config_, new_config_;
|
||||
std::unique_ptr<block::ShardConfig> old_shard_conf_; // from reference mc state
|
||||
std::unique_ptr<block::ShardConfig> new_shard_conf_; // from shard_hashes_ in mc blocks
|
||||
Ref<block::WorkchainInfo> wc_info_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> fees_import_dict_;
|
||||
bool accept_msgs_{true};
|
||||
|
||||
ton::BlockSeqno min_shard_ref_mc_seqno_{~0U};
|
||||
ton::UnixTime max_shard_utime_{0};
|
||||
ton::LogicalTime max_shard_lt_{0};
|
||||
|
||||
int global_id_{0};
|
||||
ton::BlockSeqno prev_key_block_seqno_;
|
||||
ton::BlockIdExt prev_key_block_;
|
||||
ton::LogicalTime prev_key_block_lt_;
|
||||
std::unique_ptr<block::BlockLimits> block_limits_;
|
||||
std::unique_ptr<block::BlockLimitStatus> block_limit_status_;
|
||||
|
||||
LogicalTime start_lt_, end_lt_;
|
||||
UnixTime prev_now_{~0u}, now_{~0u};
|
||||
|
||||
ton::Bits256 rand_seed_;
|
||||
std::vector<block::StoragePrices> storage_prices_;
|
||||
block::StoragePhaseConfig storage_phase_cfg_{&storage_prices_};
|
||||
block::ComputePhaseConfig compute_phase_cfg_;
|
||||
block::ActionPhaseConfig action_phase_cfg_;
|
||||
td::RefInt256 masterchain_create_fee_, basechain_create_fee_;
|
||||
|
||||
std::vector<block::McShardDescr> neighbors_;
|
||||
std::map<BlockSeqno, Ref<MasterchainStateQ>> aux_mc_states_;
|
||||
|
||||
block::ShardState ps_, ns_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> sibling_out_msg_queue_;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> sibling_processed_upto_;
|
||||
|
||||
std::unique_ptr<vm::AugmentedDictionary> in_msg_dict_, out_msg_dict_, account_blocks_dict_;
|
||||
block::ValueFlow value_flow_;
|
||||
block::CurrencyCollection import_created_, transaction_fees_;
|
||||
td::RefInt256 import_fees_;
|
||||
|
||||
ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL};
|
||||
ton::Bits256 proc_hash_, claimed_proc_hash_, min_enq_hash_;
|
||||
bool inbound_queues_empty_{false};
|
||||
|
||||
std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_proc_lt_;
|
||||
|
||||
std::vector<std::tuple<Bits256, Bits256, bool>> lib_publishers_, lib_publishers2_;
|
||||
|
||||
td::PerfWarningTimer perf_timer_{"validateblock", 0.1};
|
||||
|
||||
static constexpr td::uint32 priority() {
|
||||
return 2;
|
||||
}
|
||||
WorkchainId workchain() const {
|
||||
return shard_.workchain;
|
||||
}
|
||||
|
||||
void finish_query();
|
||||
void abort_query(td::Status error);
|
||||
bool reject_query(std::string error, td::BufferSlice reason = {});
|
||||
bool reject_query(std::string err_msg, td::Status error, td::BufferSlice reason = {});
|
||||
bool soft_reject_query(std::string error, td::BufferSlice reason = {});
|
||||
void alarm() override;
|
||||
void start_up() override;
|
||||
|
||||
bool save_candidate();
|
||||
void written_candidate();
|
||||
|
||||
bool fatal_error(td::Status error);
|
||||
bool fatal_error(int err_code, std::string err_msg);
|
||||
bool fatal_error(int err_code, std::string err_msg, td::Status error);
|
||||
bool fatal_error(std::string err_msg, int err_code = -666);
|
||||
|
||||
std::string error_ctx() const {
|
||||
return error_ctx_.as_string();
|
||||
}
|
||||
ErrorCtxAdd error_ctx_add_guard(std::string str) {
|
||||
return error_ctx_.add_guard(std::move(str));
|
||||
}
|
||||
ErrorCtxSet error_ctx_set_guard(std::string str) {
|
||||
return error_ctx_.set_guard(std::move(str));
|
||||
}
|
||||
|
||||
bool is_masterchain() const {
|
||||
return shard_.is_masterchain();
|
||||
}
|
||||
td::actor::ActorId<ValidateQuery> get_self() {
|
||||
return actor_id(this);
|
||||
}
|
||||
|
||||
void after_get_latest_mc_state(td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res);
|
||||
void after_get_mc_state(td::Result<Ref<ShardState>> res);
|
||||
void got_mc_handle(td::Result<BlockHandle> res);
|
||||
void after_get_shard_state(int idx, td::Result<Ref<ShardState>> res);
|
||||
bool process_mc_state(Ref<MasterchainState> mc_state);
|
||||
bool try_unpack_mc_state();
|
||||
bool fetch_config_params();
|
||||
bool check_prev_block(const BlockIdExt& listed, const BlockIdExt& prev, bool chk_chain_len = true);
|
||||
bool check_prev_block_exact(const BlockIdExt& listed, const BlockIdExt& prev);
|
||||
bool check_this_shard_mc_info();
|
||||
bool init_parse();
|
||||
bool unpack_block_candidate();
|
||||
bool extract_collated_data_from(Ref<vm::Cell> croot, int idx);
|
||||
bool extract_collated_data();
|
||||
bool try_validate();
|
||||
bool compute_prev_state();
|
||||
bool compute_next_state();
|
||||
bool unpack_merge_prev_state();
|
||||
bool unpack_prev_state();
|
||||
bool unpack_next_state();
|
||||
bool unpack_one_prev_state(block::ShardState& ss, BlockIdExt blkid, Ref<vm::Cell> prev_state_root);
|
||||
bool split_prev_state(block::ShardState& ss);
|
||||
bool request_neighbor_queues();
|
||||
void got_neighbor_out_queue(int i, td::Result<Ref<MessageQueue>> res);
|
||||
|
||||
bool register_mc_state(Ref<MasterchainStateQ> other_mc_state);
|
||||
bool request_aux_mc_state(BlockSeqno seqno, Ref<MasterchainStateQ>& state);
|
||||
Ref<MasterchainStateQ> get_aux_mc_state(BlockSeqno seqno) const;
|
||||
void after_get_aux_shard_state(ton::BlockIdExt blkid, td::Result<Ref<ShardState>> res);
|
||||
|
||||
bool check_one_shard(const block::McShardHash& info, const block::McShardHash* sibling,
|
||||
const block::WorkchainInfo* wc_info, const block::CatchainValidatorsConfig& ccvc);
|
||||
bool check_shard_layout();
|
||||
bool check_cur_validator_set();
|
||||
bool check_mc_validator_info(bool update_mc_cc);
|
||||
bool check_utime_lt();
|
||||
|
||||
bool fix_one_processed_upto(block::MsgProcessedUpto& proc, ton::ShardIdFull owner, bool allow_cur = false);
|
||||
bool fix_processed_upto(block::MsgProcessedUptoCollection& upto, bool allow_cur = false);
|
||||
bool fix_all_processed_upto();
|
||||
bool add_trivial_neighbor_after_merge();
|
||||
bool add_trivial_neighbor();
|
||||
bool unpack_block_data();
|
||||
bool unpack_precheck_value_flow(Ref<vm::Cell> value_flow_root);
|
||||
bool compute_minted_amount(block::CurrencyCollection& to_mint);
|
||||
bool precheck_one_account_update(td::ConstBitPtr acc_id, Ref<vm::CellSlice> old_value, Ref<vm::CellSlice> new_value);
|
||||
bool precheck_account_updates();
|
||||
bool precheck_one_transaction(td::ConstBitPtr acc_id, ton::LogicalTime trans_lt, Ref<vm::CellSlice> trans_csr,
|
||||
ton::Bits256& prev_trans_hash, ton::LogicalTime& prev_trans_lt,
|
||||
unsigned& prev_trans_lt_len, ton::Bits256& acc_state_hash);
|
||||
bool precheck_one_account_block(td::ConstBitPtr acc_id, Ref<vm::CellSlice> acc_blk);
|
||||
bool precheck_account_transactions();
|
||||
Ref<vm::Cell> lookup_transaction(const ton::StdSmcAddress& addr, ton::LogicalTime lt) const;
|
||||
bool is_valid_transaction_ref(Ref<vm::Cell> trans_ref) const;
|
||||
bool precheck_one_message_queue_update(td::ConstBitPtr out_msg_id, Ref<vm::CellSlice> old_value,
|
||||
Ref<vm::CellSlice> new_value);
|
||||
bool precheck_message_queue_update();
|
||||
bool update_max_processed_lt_hash(ton::LogicalTime lt, const ton::Bits256& hash);
|
||||
bool update_min_enqueued_lt_hash(ton::LogicalTime lt, const ton::Bits256& hash);
|
||||
bool check_imported_message(Ref<vm::Cell> msg_env);
|
||||
bool is_special_in_msg(const vm::CellSlice& in_msg) const;
|
||||
bool check_in_msg(td::ConstBitPtr key, Ref<vm::CellSlice> in_msg);
|
||||
bool check_in_msg_descr();
|
||||
bool check_out_msg(td::ConstBitPtr key, Ref<vm::CellSlice> out_msg);
|
||||
bool check_out_msg_descr();
|
||||
bool check_processed_upto();
|
||||
bool check_neighbor_outbound_message(Ref<vm::CellSlice> enq_msg, ton::LogicalTime lt, td::ConstBitPtr key,
|
||||
const block::McShardDescr& src_nb, bool& unprocessed);
|
||||
bool check_in_queue();
|
||||
bool check_delivered_dequeued();
|
||||
std::unique_ptr<block::Account> make_account_from(td::ConstBitPtr addr, Ref<vm::CellSlice> account,
|
||||
Ref<vm::CellSlice> extra);
|
||||
std::unique_ptr<block::Account> unpack_account(td::ConstBitPtr addr);
|
||||
bool check_one_transaction(block::Account& account, LogicalTime lt, Ref<vm::Cell> trans_root, bool is_first,
|
||||
bool is_last);
|
||||
bool check_account_transactions(const StdSmcAddress& acc_addr, Ref<vm::CellSlice> acc_tr);
|
||||
bool check_transactions();
|
||||
bool scan_account_libraries(Ref<vm::Cell> orig_libs, Ref<vm::Cell> final_libs, const td::Bits256& addr);
|
||||
bool check_all_ticktock_processed();
|
||||
bool check_message_processing_order();
|
||||
bool check_special_message(Ref<vm::Cell> in_msg_root, const block::CurrencyCollection& amount,
|
||||
Ref<vm::Cell> addr_cell);
|
||||
bool check_special_messages();
|
||||
bool check_one_library_update(td::ConstBitPtr key, Ref<vm::CellSlice> old_value, Ref<vm::CellSlice> new_value);
|
||||
bool check_shard_libraries();
|
||||
bool check_new_state();
|
||||
bool check_config_update(Ref<vm::CellSlice> old_conf_params, Ref<vm::CellSlice> new_conf_params);
|
||||
bool check_one_prev_dict_update(ton::BlockSeqno seqno, Ref<vm::CellSlice> old_val_extra,
|
||||
Ref<vm::CellSlice> new_val_extra);
|
||||
bool check_mc_state_extra();
|
||||
bool check_one_shard_fee(ShardIdFull shard, const block::CurrencyCollection& fees,
|
||||
const block::CurrencyCollection& create);
|
||||
bool check_mc_block_extra();
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
193
validator/impl/validator-set.cpp
Normal file
193
validator/impl/validator-set.cpp
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "validator-set.hpp"
|
||||
#include "auto/tl/ton_api.h"
|
||||
// #include "adnl/utils.hpp"
|
||||
#include "block/block.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
using td::Ref;
|
||||
|
||||
const ValidatorDescr *ValidatorSetQ::find_validator(const NodeIdShort &id) const {
|
||||
auto it =
|
||||
std::lower_bound(ids_map_.begin(), ids_map_.end(), id, [](const auto &p, const auto &x) { return p.first < x; });
|
||||
return it < ids_map_.end() && it->first == id ? &ids_[it->second] : nullptr;
|
||||
}
|
||||
|
||||
bool ValidatorSetQ::is_validator(NodeIdShort id) const {
|
||||
return find_validator(id);
|
||||
}
|
||||
|
||||
td::Result<ValidatorWeight> ValidatorSetQ::check_signatures(RootHash root_hash, FileHash file_hash,
|
||||
td::Ref<BlockSignatureSet> signatures) const {
|
||||
auto &sigs = signatures->signatures();
|
||||
|
||||
auto block = create_serialize_tl_object<ton_api::ton_blockId>(root_hash, file_hash);
|
||||
|
||||
ValidatorWeight weight = 0;
|
||||
|
||||
std::set<NodeIdShort> nodes;
|
||||
for (auto &sig : sigs) {
|
||||
if (nodes.count(sig.node) == 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "duplicate node to sign");
|
||||
}
|
||||
nodes.insert(sig.node);
|
||||
|
||||
auto vdescr = find_validator(sig.node);
|
||||
if (!vdescr) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown node to sign");
|
||||
}
|
||||
|
||||
auto E = ValidatorFullId{vdescr->key}.create_encryptor().move_as_ok();
|
||||
TRY_STATUS(E->check_signature(block.as_slice(), sig.signature.as_slice()));
|
||||
weight += vdescr->weight;
|
||||
}
|
||||
|
||||
if (weight * 3 <= total_weight_ * 2) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too small sig weight");
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
td::Result<ValidatorWeight> ValidatorSetQ::check_approve_signatures(RootHash root_hash, FileHash file_hash,
|
||||
td::Ref<BlockSignatureSet> signatures) const {
|
||||
auto &sigs = signatures->signatures();
|
||||
|
||||
auto block = create_serialize_tl_object<ton_api::ton_blockIdApprove>(root_hash, file_hash);
|
||||
|
||||
ValidatorWeight weight = 0;
|
||||
|
||||
std::set<NodeIdShort> nodes;
|
||||
for (auto &sig : sigs) {
|
||||
if (nodes.count(sig.node) == 1) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "duplicate node to sign");
|
||||
}
|
||||
nodes.insert(sig.node);
|
||||
|
||||
auto vdescr = find_validator(sig.node);
|
||||
if (!vdescr) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "unknown node to sign");
|
||||
}
|
||||
|
||||
auto E = ValidatorFullId{vdescr->key}.create_encryptor().move_as_ok();
|
||||
TRY_STATUS(E->check_signature(block.as_slice(), sig.signature.as_slice()));
|
||||
weight += vdescr->weight;
|
||||
}
|
||||
|
||||
if (weight * 3 <= total_weight_ * 2) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too small sig weight");
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
ValidatorSetQ::ValidatorSetQ(CatchainSeqno cc_seqno, ShardIdFull from, std::vector<ValidatorDescr> nodes)
|
||||
: cc_seqno_(cc_seqno), for_(from), ids_(std::move(nodes)) {
|
||||
total_weight_ = 0;
|
||||
|
||||
ids_map_.reserve(ids_.size());
|
||||
|
||||
for (std::size_t i = 0; i < ids_.size(); i++) {
|
||||
total_weight_ += ids_[i].weight;
|
||||
ids_map_.emplace_back(ValidatorFullId{ids_[i].key}.short_id(), i);
|
||||
}
|
||||
|
||||
std::sort(ids_map_.begin(), ids_map_.end());
|
||||
for (std::size_t i = 1; i < ids_map_.size(); i++) {
|
||||
CHECK(ids_map_[i - 1].first != ids_map_[i].first);
|
||||
}
|
||||
|
||||
hash_ = block::compute_validator_set_hash(cc_seqno, from, ids_);
|
||||
}
|
||||
|
||||
ValidatorSetQ *ValidatorSetQ::make_copy() const {
|
||||
return new ValidatorSetQ{*this};
|
||||
}
|
||||
|
||||
std::vector<ValidatorDescr> ValidatorSetQ::export_vector() const {
|
||||
return ids_;
|
||||
}
|
||||
|
||||
td::Status ValidatorSetCompute::init(const block::Config *config) {
|
||||
config_ = nullptr;
|
||||
cur_validators_.reset();
|
||||
next_validators_.reset();
|
||||
if (!config) {
|
||||
return td::Status::Error("null configuration pointer passed to ValidatorSetCompute");
|
||||
}
|
||||
config_ = config;
|
||||
auto cv_root = config_->get_config_param(34);
|
||||
if (cv_root.not_null()) {
|
||||
TRY_RESULT(validators, block::Config::unpack_validator_set(std::move(cv_root)));
|
||||
cur_validators_ = std::move(validators);
|
||||
}
|
||||
auto nv_root = config_->get_config_param(36);
|
||||
if (nv_root.not_null()) {
|
||||
TRY_RESULT(validators, block::Config::unpack_validator_set(std::move(nv_root)));
|
||||
next_validators_ = std::move(validators);
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> ValidatorSetCompute::compute_validator_set(ShardIdFull shard, const block::ValidatorSet &vset,
|
||||
UnixTime time, CatchainSeqno ccseqno) const {
|
||||
if (!config_) {
|
||||
return {};
|
||||
}
|
||||
LOG(DEBUG) << "in compute_validator_set() for " << shard.to_str();
|
||||
auto nodes = config_->compute_validator_set(shard, vset, time, ccseqno);
|
||||
if (nodes.empty()) {
|
||||
return {};
|
||||
}
|
||||
return Ref<ValidatorSetQ>{true, ccseqno, shard, std::move(nodes)};
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> ValidatorSetCompute::get_validator_set(ShardIdFull shard, UnixTime utime, CatchainSeqno cc) const {
|
||||
if (!config_ || !cur_validators_) {
|
||||
LOG(ERROR) << "ValidatorSetCompute::get_validator_set() : no config or no cur_validators";
|
||||
return {};
|
||||
}
|
||||
return compute_validator_set(shard, *cur_validators_, utime, cc);
|
||||
}
|
||||
|
||||
Ref<ValidatorSet> ValidatorSetCompute::get_next_validator_set(ShardIdFull shard, UnixTime utime,
|
||||
CatchainSeqno cc) const {
|
||||
if (!config_ || !cur_validators_) {
|
||||
LOG(ERROR) << "ValidatorSetCompute::get_next_validator_set() : no config or no cur_validators";
|
||||
return {};
|
||||
}
|
||||
if (!next_validators_) {
|
||||
return compute_validator_set(shard, *cur_validators_, utime, cc + 1);
|
||||
}
|
||||
bool is_mc = shard.is_masterchain();
|
||||
auto ccv_cfg = config_->get_catchain_validators_config();
|
||||
unsigned cc_lifetime = is_mc ? ccv_cfg.mc_cc_lifetime : ccv_cfg.shard_cc_lifetime;
|
||||
if (next_validators_->utime_since > (utime / cc_lifetime + 1) * cc_lifetime) {
|
||||
return compute_validator_set(shard, *cur_validators_, utime, cc + 1);
|
||||
} else {
|
||||
return compute_validator_set(shard, *next_validators_, utime, cc + 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
85
validator/impl/validator-set.hpp
Normal file
85
validator/impl/validator-set.hpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/validator-set.h"
|
||||
#include "validator/interfaces/signature-set.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "keys/encryptor.h"
|
||||
#include "block/mc-config.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorSetQ : public ValidatorSet {
|
||||
public:
|
||||
bool is_validator(NodeIdShort id) const override;
|
||||
CatchainSeqno get_catchain_seqno() const override {
|
||||
return cc_seqno_;
|
||||
}
|
||||
td::uint32 get_validator_set_hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
ShardId get_validator_set_from() const override {
|
||||
return for_.shard;
|
||||
}
|
||||
ValidatorWeight get_total_weight() const {
|
||||
return total_weight_;
|
||||
}
|
||||
std::vector<ValidatorDescr> export_vector() const override;
|
||||
td::Result<ValidatorWeight> check_signatures(RootHash root_hash, FileHash file_hash,
|
||||
td::Ref<BlockSignatureSet> signatures) const override;
|
||||
td::Result<ValidatorWeight> check_approve_signatures(RootHash root_hash, FileHash file_hash,
|
||||
td::Ref<BlockSignatureSet> signatures) const override;
|
||||
|
||||
ValidatorSetQ* make_copy() const override;
|
||||
|
||||
ValidatorSetQ(CatchainSeqno cc_seqno, ShardIdFull from, std::vector<ValidatorDescr> nodes);
|
||||
|
||||
private:
|
||||
CatchainSeqno cc_seqno_;
|
||||
ShardIdFull for_;
|
||||
td::uint32 hash_;
|
||||
ValidatorWeight total_weight_;
|
||||
std::vector<ValidatorDescr> ids_;
|
||||
std::vector<std::pair<NodeIdShort, size_t>> ids_map_;
|
||||
|
||||
const ValidatorDescr* find_validator(const NodeIdShort& id) const;
|
||||
};
|
||||
|
||||
class ValidatorSetCompute {
|
||||
public:
|
||||
td::Ref<ValidatorSet> get_validator_set(ShardIdFull shard, UnixTime utime, CatchainSeqno cc) const;
|
||||
td::Ref<ValidatorSet> get_next_validator_set(ShardIdFull shard, UnixTime utime, CatchainSeqno cc) const;
|
||||
td::Status init(const block::Config* config);
|
||||
ValidatorSetCompute() = default;
|
||||
|
||||
private:
|
||||
const block::Config* config_{nullptr};
|
||||
std::unique_ptr<block::ValidatorSet> cur_validators_, next_validators_;
|
||||
td::Ref<ValidatorSet> compute_validator_set(ShardIdFull shard, const block::ValidatorSet& vset, UnixTime time,
|
||||
CatchainSeqno seqno) const;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
105
validator/interfaces/block-handle.h
Normal file
105
validator/interfaces/block-handle.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorManagerInterface;
|
||||
|
||||
struct BlockHandleInterface {
|
||||
public:
|
||||
virtual BlockIdExt id() const = 0;
|
||||
virtual bool received() const = 0;
|
||||
virtual bool moved_to_storage() const = 0;
|
||||
virtual bool deleted() const = 0;
|
||||
virtual bool inited_next_left() const = 0;
|
||||
virtual bool inited_next_right() const = 0;
|
||||
virtual bool inited_next() const = 0;
|
||||
virtual bool inited_prev_left() const = 0;
|
||||
virtual bool inited_prev_right() const = 0;
|
||||
virtual bool inited_prev() const = 0;
|
||||
virtual bool inited_logical_time() const = 0;
|
||||
virtual bool inited_unix_time() const = 0;
|
||||
virtual bool inited_proof() const = 0;
|
||||
virtual bool inited_proof_link() const = 0;
|
||||
virtual bool inited_signatures() const = 0;
|
||||
virtual bool inited_split_after() const = 0;
|
||||
virtual bool inited_merge_before() const = 0;
|
||||
virtual bool inited_is_key_block() const = 0;
|
||||
virtual bool split_after() const = 0;
|
||||
virtual bool merge_before() const = 0;
|
||||
virtual bool is_key_block() const = 0;
|
||||
virtual bool inited_state_root_hash() const = 0;
|
||||
virtual bool received_state() const = 0;
|
||||
virtual bool inited_state_boc() const = 0;
|
||||
virtual bool deleted_state_boc() const = 0;
|
||||
virtual bool need_flush() const = 0;
|
||||
virtual bool is_zero() const = 0;
|
||||
virtual bool is_archived() const = 0;
|
||||
virtual bool is_applied() const = 0;
|
||||
virtual std::vector<BlockIdExt> prev() const = 0;
|
||||
virtual BlockIdExt one_prev(bool left) const = 0;
|
||||
virtual std::vector<BlockIdExt> next() const = 0;
|
||||
virtual BlockIdExt one_next(bool left) const = 0;
|
||||
virtual RootHash state() const = 0;
|
||||
virtual td::uint32 version() const = 0;
|
||||
|
||||
virtual bool processed() const = 0;
|
||||
virtual void set_processed() = 0;
|
||||
|
||||
virtual void flush(td::actor::ActorId<ValidatorManagerInterface> manager, std::shared_ptr<BlockHandleInterface> self,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void flushed_upto(td::uint32 version) = 0;
|
||||
virtual void set_logical_time(LogicalTime lt) = 0;
|
||||
virtual void set_unix_time(UnixTime ts) = 0;
|
||||
virtual LogicalTime logical_time() const = 0;
|
||||
virtual UnixTime unix_time() const = 0;
|
||||
virtual void set_proof() = 0;
|
||||
virtual void set_proof_link() = 0;
|
||||
virtual void set_signatures() = 0;
|
||||
virtual void set_next(BlockIdExt next) = 0;
|
||||
virtual void set_prev(BlockIdExt prev) = 0;
|
||||
virtual void set_received() = 0;
|
||||
virtual void set_moved_to_storage() = 0;
|
||||
virtual void set_deleted() = 0;
|
||||
virtual void set_split(bool value) = 0;
|
||||
virtual void set_merge(bool value) = 0;
|
||||
virtual void set_is_key_block(bool value) = 0;
|
||||
virtual void set_state_root_hash(RootHash hash) = 0;
|
||||
virtual void set_state_boc() = 0;
|
||||
virtual void set_deleted_state_boc() = 0;
|
||||
virtual void set_archived() = 0;
|
||||
virtual void set_applied() = 0;
|
||||
|
||||
virtual td::BufferSlice serialize() const = 0;
|
||||
|
||||
virtual ~BlockHandleInterface() = default;
|
||||
};
|
||||
|
||||
using BlockHandle = std::shared_ptr<BlockHandleInterface>;
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
39
validator/interfaces/block.h
Normal file
39
validator/interfaces/block.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class BlockData : public td::CntObject {
|
||||
public:
|
||||
virtual ~BlockData() = default;
|
||||
|
||||
virtual td::BufferSlice data() const = 0;
|
||||
virtual FileHash file_hash() const = 0;
|
||||
virtual BlockIdExt block_id() const = 0;
|
||||
virtual td::Ref<vm::Cell> root_cell() const = 0;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
41
validator/interfaces/config.h
Normal file
41
validator/interfaces/config.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "crypto/common/refcnt.hpp"
|
||||
#include "validator-set.h"
|
||||
#include "crypto/block/mc-config.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
using McShardHash = block::McShardHashI;
|
||||
|
||||
class ConfigHolder : public td::CntObject {
|
||||
public:
|
||||
virtual ~ConfigHolder() = default;
|
||||
|
||||
virtual td::Ref<ValidatorSet> get_total_validator_set(int next) const = 0; // next = -1 -> prev, next = 0 -> cur
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
98
validator/interfaces/db.h
Normal file
98
validator/interfaces/db.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
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/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "validator/interfaces/block-handle.h"
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class Db : public td::actor::Actor {
|
||||
public:
|
||||
virtual ~Db() = default;
|
||||
|
||||
virtual void store_block_data(BlockHandle handle, td::Ref<BlockData> data, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_data(BlockHandle handle, td::Promise<td::Ref<BlockData>> promise) = 0;
|
||||
|
||||
virtual void store_block_signatures(BlockHandle handle, td::Ref<BlockSignatureSet> data,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockSignatureSet>> promise) = 0;
|
||||
|
||||
virtual void store_block_proof(BlockHandle handle, td::Ref<Proof> proof, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_proof(BlockHandle handle, td::Promise<td::Ref<Proof>> promise) = 0;
|
||||
|
||||
virtual void store_block_proof_link(BlockHandle handle, td::Ref<ProofLink> proof, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_proof_link(BlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) = 0;
|
||||
|
||||
virtual void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_candidate(ton::PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
|
||||
td::Promise<BlockCandidate> promise) = 0;
|
||||
|
||||
virtual void store_block_state(BlockHandle handle, td::Ref<ShardState> state,
|
||||
td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
virtual void get_block_state(BlockHandle handle, td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
|
||||
virtual void store_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::BufferSlice state,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void check_persistent_state_file_exists(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<bool> promise) = 0;
|
||||
virtual void store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_zero_state_file(BlockIdExt block_id, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void check_zero_state_file_exists(BlockIdExt block_id, td::Promise<bool> promise) = 0;
|
||||
|
||||
virtual void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) = 0;
|
||||
|
||||
//virtual void store_zero_state(ZeroStateIdExt id, td::Ref<ShardState> state, td::Promise<td::Unit> promise) = 0;
|
||||
//virtual void get_zero_state(ZeroStateIdExt id, td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
|
||||
virtual void store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) = 0;
|
||||
|
||||
virtual void apply_block(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_block_by_lt(AccountIdPrefixFull account, LogicalTime lt, td::Promise<BlockIdExt> promise) = 0;
|
||||
virtual void get_block_by_unix_time(AccountIdPrefixFull account, UnixTime ts, td::Promise<BlockIdExt> promise) = 0;
|
||||
virtual void get_block_by_seqno(AccountIdPrefixFull account, BlockSeqno seqno, td::Promise<BlockIdExt> promise) = 0;
|
||||
|
||||
virtual void update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_init_masterchain_block(td::Promise<BlockIdExt> promise) = 0;
|
||||
|
||||
virtual void update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_gc_masterchain_block(td::Promise<BlockIdExt> promise) = 0;
|
||||
|
||||
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_shard_client_state(td::Promise<BlockIdExt> promise) = 0;
|
||||
|
||||
virtual void update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) = 0;
|
||||
|
||||
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;
|
||||
|
||||
virtual void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) = 0;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue