1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-15 04:32:21 +00:00

Merge branch 'testnet' into block-generation

This commit is contained in:
SpyCheese 2024-03-26 16:19:34 +03:00
commit 7999a7e2c1
52 changed files with 1466 additions and 282 deletions

39
CMake/FindLZ4.cmake Normal file
View file

@ -0,0 +1,39 @@
###############################################################################
# Find LZ4
#
# This sets the following variables:
# LZ4_FOUND - True if LZ4 was found.
# LZ4_INCLUDE_DIRS - Directories containing the LZ4 include files.
# LZ4_LIBRARIES - Libraries needed to use LZ4.
# LZ4_LIBRARY - Library needed to use LZ4.
# LZ4_LIBRARY_DIRS - Library needed to use LZ4.
find_package(PkgConfig REQUIRED)
# If found, LZ$_* variables will be defined
pkg_check_modules(LZ4 REQUIRED liblz4)
if(NOT LZ4_FOUND)
find_path(LZ4_INCLUDE_DIR lz4.h
HINTS "${LZ4_ROOT}" "$ENV{LZ4_ROOT}"
PATHS "$ENV{PROGRAMFILES}/lz4" "$ENV{PROGRAMW6432}/lz4"
PATH_SUFFIXES include)
find_library(LZ4_LIBRARY
NAMES lz4 lz4_static
HINTS "${LZ4_ROOT}" "$ENV{LZ4_ROOT}"
PATHS "$ENV{PROGRAMFILES}/lz4" "$ENV{PROGRAMW6432}/lz4"
PATH_SUFFIXES lib)
if(LZ4_LIBRARY)
set(LZ4_LIBRARIES ${LZ4_LIBRARY})
get_filename_component(LZ4_LIBRARY_DIRS ${LZ4_LIBRARY} DIRECTORY)
endif()
else()
find_library(LZ4_LIBRARY
NAMES lz4 lz4_static
PATHS ${LZ4_LIBRARY_DIRS}
NO_DEFAULT_PATH)
endif()
mark_as_advanced(LZ4_LIBRARY LZ4_INCLUDE_DIRS LZ4_LIBRARY_DIRS LZ4_LIBRARIES)

View file

@ -13,7 +13,7 @@ All configuration parameters are combined into a *configuration dictionary* - a
We see that, apart from the configuration dictionary, `ConfigParams` contains `config_addr` -- 256-bit address of the configuration smart contract in the masterchain. More details on the configuration smart contract will be provided later.
The configuration dictionary containing the active values of all configuration parameters is available via special TVM register *c7* to all smart contracts when their code is executed in a transaction. More precisely, when a smart contract is executed, *c7* is initialized by a Tuple, the only element of which is a Tuple with several "context" values useful for the execution of the smart contract, such as the current Unix time (as registered in the block header). The tenth entry of this Tuple (i.e., the one with zero-based index 9) contains a Cell representing the configuration dictionary. Therefore, it can be accesses by means of TVM instructions "PUSH c7; FIRST; INDEX 9", or by equivalent instruction "CONFIGROOT". In fact, special TVM instructions "CONFIGPARAM" and "CONFIGOPTPARAM" combine the previous actions with a dictionary lookup, returning any configuration parameter by its index. We refer to the TVM documentation for more details on these instructions. What is relevant here is that all configuration parameters are easily accessible from all smart contracts (masterchain or shardchain), and smart contracts may inspect them and use them to perform specific checks. For instance, a smart contract might extract workchain data storage prices from a configuration parameter to compute the price for storing a chunk of user-provided data.
The configuration dictionary containing the active values of all configuration parameters is available via special TVM register *c7* to all smart contracts when their code is executed in a transaction. More precisely, when a smart contract is executed, *c7* is initialized by a Tuple, the only element of which is a Tuple with several "context" values useful for the execution of the smart contract, such as the current Unix time (as registered in the block header). The tenth entry of this Tuple (i.e., the one with zero-based index 9) contains a Cell representing the configuration dictionary. Therefore, it can be accessed by means of TVM instructions "PUSH c7; FIRST; INDEX 9", or by equivalent instruction "CONFIGROOT". In fact, special TVM instructions "CONFIGPARAM" and "CONFIGOPTPARAM" combine the previous actions with a dictionary lookup, returning any configuration parameter by its index. We refer to the TVM documentation for more details on these instructions. What is relevant here is that all configuration parameters are easily accessible from all smart contracts (masterchain or shardchain), and smart contracts may inspect them and use them to perform specific checks. For instance, a smart contract might extract workchain data storage prices from a configuration parameter to compute the price for storing a chunk of user-provided data.
The values of configuration parameters are not arbitrary. In fact, if the configuration parameter index *i* is non-negative, then the value of this parameter must be a valid value of TL-B type (ConfigParam i). This restriction is enforced by the validators, which will not accept changes to configuration parameters with non-negative indices unless they are valid values of the corresponding TL-B type.

View file

@ -13,8 +13,8 @@ For catchain protocol version higher or equal to 2 hash covers catchain block de
### Catchain block size
All catchain messages, except `REJECT` message, have (and had) a limited size. After update `REJECT` message will be limited to 1024 bytes. At the same time one block contains at most number of block candidates per round messages. That way, 16kb limit per catchain block should be enough to prevent DoS.
### Limiting block height
Another potential DoS is related to a situation when a malbehaviouring node sends too many catchain blocks. Note that limiting of maximal number of blocks per second is not a good solution since it will hinder synchronization after node disconnect.
At the same time, catchain groups exist for quite short period of time (around a few hunderd seconds), while number of blocks production is determined by "natural block production speed" on the one hand and number of blocks generated to decrease dependencies size on the other. In any case, total number of blocks is limited by `catchain_lifetime * natural_block_production_speed * (1 + number_of_catchain_participants / max_dependencies_size)`.
Another potential DoS is related to a situation when a misbehaviouring node sends too many catchain blocks. Note that limiting of maximal number of blocks per second is not a good solution since it will hinder synchronization after node disconnect.
At the same time, catchain groups exist for quite short period of time (around a few hundred seconds), while number of blocks production is determined by "natural block production speed" on the one hand and number of blocks generated to decrease dependencies size on the other. In any case, total number of blocks is limited by `catchain_lifetime * natural_block_production_speed * (1 + number_of_catchain_participants / max_dependencies_size)`.
To prevent DoS attack we limit maximal height of the block which will be processed by node by `catchain_lifetime * natural_block_production_speed * (1 + number_of_catchain_participants / max_dependencies_size)`, where `catchain_lifetime` is set by `ConfigParam 28` (`CatchainConfig`), `natural_block_production_speed` and `max_dependencies_size` are set by `ConfigParam 29` (`ConsensusConfig`) (`natural_block_production_speed` is calculated as `catchain_max_blocks_coeff / 1000`) and `number_of_catchain_participants` is set from catchain group configuration.
By default, `catchain_max_blocks_coeff` is set to zero: special value which means that there is no limitation on catchain block height. It is recommended to set `catchain_max_blocks_coeff` to `10000`: we expect that natural production rate is about one block per 3 seconds, so we set the coefficient to allow 30 times higher block production than expected. At the same time, this number is low enough to prevent resource-intensive attacks.

View file

@ -1100,6 +1100,7 @@ bool TestNode::show_help(std::string command) {
"savecomplaints <election-id> <filename-pfx>\tSaves all complaints registered for specified validator set id "
"into files <filename-pfx><complaint-hash>.boc\n"
"complaintprice <expires-in> <complaint-boc>\tComputes the price (in nanograms) for creating a complaint\n"
"msgqueuesizes\tShows current sizes of outbound message queues in all shards\n"
"known\tShows the list of all known block ids\n"
"knowncells\tShows the list of hashes of all known (cached) cells\n"
"dumpcell <hex-hash-pfx>\nDumps a cached cell by a prefix of its hash\n"
@ -1235,6 +1236,8 @@ bool TestNode::do_parse_line() {
std::string filename;
return parse_uint32(expire_in) && get_word_to(filename) && seekeoln() &&
set_error(get_complaint_price(expire_in, filename));
} else if (word == "msgqueuesizes") {
return get_msg_queue_sizes();
} else if (word == "known") {
return eoln() && show_new_blkids(true);
} else if (word == "knowncells") {
@ -1744,6 +1747,31 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add
std::move(P));
}
bool TestNode::get_msg_queue_sizes() {
// TODO: rework for separated liteservers
auto q = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOutMsgQueueSizes>(0, 0, 0), true);
return envelope_send_query_to_any(std::move(q), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
if (res.is_error()) {
LOG(ERROR) << "liteServer.getOutMsgQueueSizes error: " << res.move_as_error();
return;
}
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_outMsgQueueSizes>(res.move_as_ok(), true);
if (F.is_error()) {
LOG(ERROR) << "cannot parse answer to liteServer.getOutMsgQueueSizes";
return;
}
td::actor::send_closure_later(Self, &TestNode::got_msg_queue_sizes, F.move_as_ok());
});
}
void TestNode::got_msg_queue_sizes(ton::tl_object_ptr<ton::lite_api::liteServer_outMsgQueueSizes> f) {
td::TerminalIO::out() << "Outbound message queue sizes:" << std::endl;
for (auto &x : f->shards_) {
td::TerminalIO::out() << ton::create_block_id(x->id_).id.to_str() << " " << x->size_ << std::endl;
}
td::TerminalIO::out() << "External message queue size limit: " << f->ext_msg_queue_size_limit_ << std::endl;
}
bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
std::string domain, td::Bits256 cat, int mode) {
if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') {

View file

@ -35,6 +35,7 @@
#include "block/block.h"
#include "block/mc-config.h"
#include "td/utils/filesystem.h"
#include "auto/tl/lite_api.h"
using td::Ref;
@ -315,6 +316,8 @@ class TestNode : public td::actor::Actor {
td::Bits256 chash = td::Bits256::zero(), std::string filename = "");
void send_compute_complaint_price_query(ton::StdSmcAddress elector_addr, unsigned expires_in, unsigned bits,
unsigned refs, td::Bits256 chash, std::string filename);
bool get_msg_queue_sizes();
void got_msg_queue_sizes(ton::tl_object_ptr<ton::lite_api::liteServer_outMsgQueueSizes> f);
bool cache_cell(Ref<vm::Cell> cell);
bool list_cached_cells() const;
bool dump_cached_cell(td::Slice hash_pfx, td::Slice type_name = {});

View file

@ -324,7 +324,7 @@ td::Status Torrent::add_piece(td::uint64 piece_i, td::Slice data, td::Ref<vm::Ce
piece_is_ready_[piece_i] = true;
ready_parts_count_++;
if (chunks_.empty() || !enabled_wirte_to_files_) {
if (chunks_.empty() || !enabled_write_to_files_) {
return add_pending_piece(piece_i, data);
}
return add_validated_piece(piece_i, data);
@ -357,7 +357,7 @@ td::Status Torrent::add_pending_piece(td::uint64 piece_i, td::Slice data) {
fatal_error_ = S.clone();
return S;
}
if (enabled_wirte_to_files_) {
if (enabled_write_to_files_) {
add_pending_pieces();
}
}
@ -367,10 +367,10 @@ td::Status Torrent::add_pending_piece(td::uint64 piece_i, td::Slice data) {
}
void Torrent::enable_write_to_files() {
if (enabled_wirte_to_files_) {
if (enabled_write_to_files_) {
return;
}
enabled_wirte_to_files_ = true;
enabled_write_to_files_ = true;
if (header_) {
add_pending_pieces();
}
@ -441,7 +441,7 @@ td::Status Torrent::add_validated_piece(td::uint64 piece_i, td::Slice data) {
}
bool Torrent::is_completed() const {
return inited_info_ && enabled_wirte_to_files_ && included_ready_size_ == included_size_;
return inited_info_ && enabled_write_to_files_ && included_ready_size_ == included_size_;
}
td::Result<td::BufferSlice> Torrent::read_file(td::Slice name) {
@ -488,7 +488,7 @@ Torrent::Torrent(Info info, td::optional<TorrentHeader> header, ton::MerkleTree
, info_(info)
, root_dir_(std::move(root_dir))
, header_(std::move(header))
, enabled_wirte_to_files_(true)
, enabled_write_to_files_(true)
, merkle_tree_(std::move(tree))
, piece_is_ready_(info_.pieces_count(), true)
, ready_parts_count_{info_.pieces_count()}
@ -586,7 +586,7 @@ void Torrent::set_file_excluded(size_t i, bool excluded) {
included_ready_size_ += chunk.ready_size;
}
chunk.excluded = excluded;
if (!enabled_wirte_to_files_ || excluded) {
if (!enabled_write_to_files_ || excluded) {
return;
}
auto range = get_file_parts_range(i);

View file

@ -173,7 +173,7 @@ class Torrent {
size_t not_ready_pending_piece_count_{0};
size_t header_pieces_count_{0};
std::map<td::uint64, td::string> pending_pieces_;
bool enabled_wirte_to_files_ = false;
bool enabled_write_to_files_ = false;
struct InMemoryPiece {
std::string data;
std::set<size_t> pending_chunks;

View file

@ -15,6 +15,7 @@ if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
endif()
find_package(PkgConfig REQUIRED)
find_package(LZ4)
if (NOT ZLIB_FOUND)
pkg_check_modules(ZLIB zlib)
endif()
@ -280,6 +281,15 @@ if (TDUTILS_MIME_TYPE)
)
endif()
if (LZ4_FOUND)
set(TD_HAVE_LZ4 1)
set(TDUTILS_SOURCE
${TDUTILS_SOURCE}
td/utils/lz4.cpp
td/utils/lz4.h
)
endif()
set(TDUTILS_TEST_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/test/buffer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ConcurrentHashMap.cpp
@ -338,6 +348,11 @@ endif()
if (CRC32C_FOUND)
target_link_libraries(tdutils PRIVATE crc32c)
endif()
if (LZ4_FOUND)
target_link_libraries(tdutils PRIVATE ${LZ4_LIBRARIES})
endif()
if (ABSL_FOUND)
target_link_libraries_system(tdutils absl::flat_hash_map absl::flat_hash_set absl::hash)
endif()

View file

@ -3,6 +3,7 @@
#cmakedefine01 TD_HAVE_OPENSSL
#cmakedefine01 TD_HAVE_ZLIB
#cmakedefine01 TD_HAVE_CRC32C
#cmakedefine01 TD_HAVE_LZ4
#cmakedefine01 TD_HAVE_COROUTINES
#cmakedefine01 TD_HAVE_ABSL
#cmakedefine01 TD_FD_DEBUG

48
tdutils/td/utils/lz4.cpp Normal file
View file

@ -0,0 +1,48 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "td/utils/buffer.h"
#include "td/utils/misc.h"
#include <lz4.h>
namespace td {
td::BufferSlice lz4_compress(td::Slice data) {
int size = narrow_cast<int>(data.size());
int buf_size = LZ4_compressBound(size);
td::BufferSlice compressed(buf_size);
int compressed_size = LZ4_compress_default(data.data(), compressed.data(), size, buf_size);
CHECK(compressed_size > 0);
return td::BufferSlice{compressed.as_slice().substr(0, compressed_size)};
}
td::Result<td::BufferSlice> lz4_decompress(td::Slice data, int max_decompressed_size) {
TRY_RESULT(size, narrow_cast_safe<int>(data.size()));
if (max_decompressed_size < 0) {
return td::Status::Error("invalid max_decompressed_size");
}
td::BufferSlice decompressed(max_decompressed_size);
int result = LZ4_decompress_safe(data.data(), decompressed.data(), size, max_decompressed_size);
if (result < 0) {
return td::Status::Error(PSTRING() << "lz4 decompression failed, error code: " << result);
}
if (result == max_decompressed_size) {
return decompressed;
}
return td::BufferSlice{decompressed.as_slice().substr(0, result)};
}
} // namespace td

27
tdutils/td/utils/lz4.h Normal file
View file

@ -0,0 +1,27 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "td/utils/buffer.h"
#include "td/utils/Status.h"
namespace td {
td::BufferSlice lz4_compress(td::Slice data);
td::Result<td::BufferSlice> lz4_decompress(td::Slice data, int max_decompressed_size);
} // namespace td

View file

@ -148,6 +148,7 @@ std::string lite_query_name_by_id(int id) {
{lite_api::liteServer_getOneTransaction::ID, "getOneTransaction"},
{lite_api::liteServer_getTransactions::ID, "getTransactions"},
{lite_api::liteServer_lookupBlock::ID, "lookupBlock"},
{lite_api::liteServer_lookupBlockWithProof::ID, "lookupBlockWithProof"},
{lite_api::liteServer_listBlockTransactions::ID, "listBlockTransactions"},
{lite_api::liteServer_listBlockTransactionsExt::ID, "listBlockTransactionsExt"},
{lite_api::liteServer_getBlockProof::ID, "getBlockProof"},
@ -155,7 +156,11 @@ std::string lite_query_name_by_id(int id) {
{lite_api::liteServer_getConfigParams::ID, "getConfigParams"},
{lite_api::liteServer_getValidatorStats::ID, "getValidatorStats"},
{lite_api::liteServer_getLibraries::ID, "getLibraries"},
{lite_api::liteServer_getShardBlockProof::ID, "getShardBlockProof"}};
{lite_api::liteServer_getLibrariesWithProof::ID, "getLibrariesWithProof"},
{lite_api::liteServer_getShardBlockProof::ID, "getShardBlockProof"},
{lite_api::liteServer_getOutMsgQueueSizes::ID, "getOutMsgQueueSizes"},
{lite_api::liteServer_nonfinal_getCandidate::ID, "nonfinal.getCandidate"},
{lite_api::liteServer_nonfinal_getValidatorGroups::ID, "nonfinal.getValidatorGroups"}};
auto it = names.find(id);
if (it == names.end()) {
return "unknown";

View file

@ -57,9 +57,17 @@ liteServer.libraryResultWithProof id:tonNode.blockIdExt mode:# result:(vector li
liteServer.shardBlockLink id:tonNode.blockIdExt proof:bytes = liteServer.ShardBlockLink;
liteServer.shardBlockProof masterchain_id:tonNode.blockIdExt links:(vector liteServer.shardBlockLink) = liteServer.ShardBlockProof;
liteServer.lookupBlockResult id:tonNode.blockIdExt mode:# mc_block_id:tonNode.blockIdExt client_mc_state_proof:bytes mc_block_proof:bytes shard_links:(vector liteServer.shardBlockLink) header:bytes prev_header:bytes = liteServer.LookupBlockResult;
liteServer.outMsgQueueSize id:tonNode.blockIdExt size:int = liteServer.OutMsgQueueSize;
liteServer.outMsgQueueSizes shards:(vector liteServer.outMsgQueueSize) ext_msg_queue_size_limit:int = liteServer.OutMsgQueueSizes;
liteServer.debug.verbosity value:int = liteServer.debug.Verbosity;
liteServer.nonfinal.candidateId block_id:tonNode.blockIdExt creator:int256 collated_data_hash:int256 = liteServer.nonfinal.CandidateId;
liteServer.nonfinal.candidate id:liteServer.nonfinal.candidateId data:bytes collated_data:bytes = liteServer.nonfinal.Candidate;
liteServer.nonfinal.candidateInfo id:liteServer.nonfinal.candidateId available:Bool approved_weight:long signed_weight:long total_weight:long = liteServer.nonfinal.CandidateInfo;
liteServer.nonfinal.validatorGroupInfo next_block_id:tonNode.blockId cc_seqno:int prev:(vector tonNode.blockIdExt) candidates:(vector liteServer.nonfinal.candidateInfo) = liteServer.nonfinal.ValidatorGroupInfo;
liteServer.nonfinal.validatorGroups groups:(vector liteServer.nonfinal.validatorGroupInfo) = liteServer.nonfinal.ValidatorGroups;
---functions---
liteServer.getMasterchainInfo = liteServer.MasterchainInfo;
@ -88,6 +96,10 @@ liteServer.getValidatorStats#091a58bc mode:# id:tonNode.blockIdExt limit:int sta
liteServer.getLibraries library_list:(vector int256) = liteServer.LibraryResult;
liteServer.getLibrariesWithProof id:tonNode.blockIdExt mode:# library_list:(vector int256) = liteServer.LibraryResultWithProof;
liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof;
liteServer.getOutMsgQueueSizes mode:# wc:mode.0?int shard:mode.0?long = liteServer.OutMsgQueueSizes;
liteServer.nonfinal.getValidatorGroups mode:# wc:mode.0?int shard:mode.1?long = liteServer.nonfinal.ValidatorGroups;
liteServer.nonfinal.getCandidate id:liteServer.nonfinal.candidateId = liteServer.nonfinal.Candidate;
liteServer.queryPrefix = Object;
liteServer.query data:bytes = Object;

Binary file not shown.

View file

@ -309,6 +309,7 @@ validatorSession.candidateId src:int256 root_hash:int256 file_hash:int256 collat
validatorSession.blockUpdate ts:long actions:(vector validatorSession.round.Message) state:int = validatorSession.BlockUpdate;
validatorSession.candidate src:int256 round:int root_hash:int256 data:bytes collated_data:bytes = validatorSession.Candidate;
validatorSession.compressedCandidate flags:# src:int256 round:int root_hash:int256 decompressed_size:int data:bytes = validatorSession.Candidate;
validatorSession.config catchain_idle_timeout:double catchain_max_deps:int round_candidates:int next_candidate_delay:double round_attempt_duration:int
max_round_attempts:int max_block_size:int max_collated_data_size:int = validatorSession.Config;
@ -386,9 +387,13 @@ tonNode.externalMessage data:bytes = tonNode.ExternalMessage;
tonNode.newShardBlock block:tonNode.blockIdExt cc_seqno:int data:bytes = tonNode.NewShardBlock;
tonNode.blockBroadcastCompressed.data signatures:(vector tonNode.blockSignature) proof_data:bytes = tonNode.blockBroadcaseCompressed.Data;
tonNode.blockBroadcast id:tonNode.blockIdExt catchain_seqno:int validator_set_hash:int
signatures:(vector tonNode.blockSignature)
proof:bytes data:bytes = tonNode.Broadcast;
tonNode.blockBroadcastCompressed id:tonNode.blockIdExt catchain_seqno:int validator_set_hash:int
flags:# compressed:bytes = tonNode.Broadcast;
tonNode.ihrMessageBroadcast message:tonNode.ihrMessage = tonNode.Broadcast;
tonNode.externalMessageBroadcast message:tonNode.externalMessage = tonNode.Broadcast;
tonNode.newShardBlockBroadcast block:tonNode.newShardBlock = tonNode.Broadcast;
@ -403,9 +408,8 @@ tonNode.keyBlocks blocks:(vector tonNode.blockIdExt) incomplete:Bool error:Bool
ton.blockId root_cell_hash:int256 file_hash:int256 = ton.BlockId;
ton.blockIdApprove root_cell_hash:int256 file_hash:int256 = ton.BlockId;
tonNode.dataList data:(vector bytes) = tonNode.DataList;
tonNode.dataFull id:tonNode.blockIdExt proof:bytes block:bytes is_link:Bool = tonNode.DataFull;
tonNode.dataFullCompressed id:tonNode.blockIdExt flags:# compressed:bytes is_link:Bool = tonNode.DataFull;
tonNode.dataFullEmpty = tonNode.DataFull;
tonNode.capabilities#f5bf60c0 version_major:int version_minor:int flags:# = tonNode.Capabilities;
@ -438,18 +442,13 @@ tonNode.getNextKeyBlockIds block:tonNode.blockIdExt max_size:int = tonNode.KeyBl
tonNode.downloadNextBlockFull prev_block:tonNode.blockIdExt = tonNode.DataFull;
tonNode.downloadBlockFull block:tonNode.blockIdExt = tonNode.DataFull;
tonNode.downloadBlock block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadBlocks blocks:(vector tonNode.blockIdExt) = tonNode.DataList;
tonNode.downloadPersistentState block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadPersistentStateSlice block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt offset:long max_size:long = tonNode.Data;
tonNode.downloadZeroState block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadBlockProof block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadKeyBlockProof block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadBlockProofs blocks:(vector tonNode.blockIdExt) = tonNode.DataList;
tonNode.downloadKeyBlockProofs blocks:(vector tonNode.blockIdExt) = tonNode.DataList;
tonNode.downloadBlockProofLink block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadKeyBlockProofLink block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadBlockProofLinks blocks:(vector tonNode.blockIdExt) = tonNode.DataList;
tonNode.downloadKeyBlockProofLinks blocks:(vector tonNode.blockIdExt) = tonNode.DataList;
tonNode.getArchiveInfo masterchain_seqno:int = tonNode.ArchiveInfo;
tonNode.getArchiveSlice archive_id:long offset:long max_size:int = tonNode.Data;
tonNode.getOutMsgQueueProof dst_shard:tonNode.shardId blocks:(vector tonNode.blockIdExt)

Binary file not shown.

View file

@ -1428,6 +1428,7 @@ td::Status ValidatorEngine::load_global_config() {
validator_options_.write().set_max_open_archive_files(max_open_archive_files_);
validator_options_.write().set_archive_preload_period(archive_preload_period_);
validator_options_.write().set_disable_rocksdb_stats(disable_rocksdb_stats_);
validator_options_.write().set_nonfinal_ls_queries_enabled(nonfinal_ls_queries_enabled_);
std::vector<ton::BlockIdExt> h;
for (auto &x : conf.validator_->hardforks_) {
@ -4131,6 +4132,9 @@ int main(int argc, char *argv[]) {
p.add_option('\0', "disable-rocksdb-stats", "disable gathering rocksdb statistics (enabled by default)", [&]() {
acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_disable_rocksdb_stats, true); });
});
p.add_option('\0', "nonfinal-ls", "enable special LS queries to non-finalized blocks", [&]() {
acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_nonfinal_ls_queries_enabled); });
});
auto S = p.run(argc, argv);
if (S.is_error()) {
LOG(ERROR) << "failed to parse options: " << S.move_as_error();

View file

@ -221,6 +221,7 @@ class ValidatorEngine : public td::actor::Actor {
size_t max_open_archive_files_ = 0;
double archive_preload_period_ = 0.0;
bool disable_rocksdb_stats_ = false;
bool nonfinal_ls_queries_enabled_ = false;
bool read_config_ = false;
bool started_keyring_ = false;
bool started_ = false;
@ -293,6 +294,9 @@ class ValidatorEngine : public td::actor::Actor {
void set_disable_rocksdb_stats(bool value) {
disable_rocksdb_stats_ = value;
}
void set_nonfinal_ls_queries_enabled() {
nonfinal_ls_queries_enabled_ = true;
}
void set_not_all_shards() {
not_all_shards_ = true;
}

View file

@ -5,12 +5,14 @@ if (NOT OPENSSL_FOUND)
endif()
set(VALIDATOR_SESSION_SOURCE
candidate-serializer.cpp
persistent-vector.cpp
validator-session-description.cpp
validator-session-state.cpp
validator-session.cpp
validator-session-round-attempt-state.cpp
candidate-serializer.h
persistent-vector.h
validator-session-description.h
validator-session-description.hpp

View file

@ -0,0 +1,76 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "candidate-serializer.h"
#include "tl-utils/tl-utils.hpp"
#include "vm/boc.h"
#include "td/utils/lz4.h"
#include "validator-session-types.h"
namespace ton::validatorsession {
td::Result<td::BufferSlice> serialize_candidate(const tl_object_ptr<ton_api::validatorSession_candidate> &block,
bool compression_enabled) {
if (!compression_enabled) {
return serialize_tl_object(block, true);
}
vm::BagOfCells boc1, boc2;
TRY_STATUS(boc1.deserialize(block->data_));
if (boc1.get_root_count() != 1) {
return td::Status::Error("block candidate should have exactly one root");
}
std::vector<td::Ref<vm::Cell>> roots = {boc1.get_root_cell()};
TRY_STATUS(boc2.deserialize(block->collated_data_));
for (int i = 0; i < boc2.get_root_count(); ++i) {
roots.push_back(boc2.get_root_cell(i));
}
TRY_RESULT(data, vm::std_boc_serialize_multi(std::move(roots), 2));
td::BufferSlice compressed = td::lz4_compress(data);
LOG(VALIDATOR_SESSION_DEBUG) << "Compressing block candidate: " << block->data_.size() + block->collated_data_.size()
<< " -> " << compressed.size();
return create_serialize_tl_object<ton_api::validatorSession_compressedCandidate>(
0, block->src_, block->round_, block->root_hash_, (int)data.size(), std::move(compressed));
}
td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data,
bool compression_enabled,
int max_decompressed_data_size) {
if (!compression_enabled) {
return fetch_tl_object<ton_api::validatorSession_candidate>(data, true);
}
TRY_RESULT(f, fetch_tl_object<ton_api::validatorSession_compressedCandidate>(data, true));
if (f->decompressed_size_ > max_decompressed_data_size) {
return td::Status::Error("decompressed size is too big");
}
TRY_RESULT(decompressed, td::lz4_decompress(f->data_, f->decompressed_size_));
if (decompressed.size() != (size_t)f->decompressed_size_) {
return td::Status::Error("decompressed size mismatch");
}
TRY_RESULT(roots, vm::std_boc_deserialize_multi(decompressed));
if (roots.empty()) {
return td::Status::Error("boc is empty");
}
TRY_RESULT(block_data, vm::std_boc_serialize(roots[0], 31));
roots.erase(roots.begin());
TRY_RESULT(collated_data, vm::std_boc_serialize_multi(std::move(roots), 31));
LOG(VALIDATOR_SESSION_DEBUG) << "Decompressing block candidate: " << f->data_.size() << " -> "
<< block_data.size() + collated_data.size();
return create_tl_object<ton_api::validatorSession_candidate>(f->src_, f->round_, f->root_hash_, std::move(block_data),
std::move(collated_data));
}
} // namespace ton::validatorsession

View file

@ -0,0 +1,29 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ton/ton-types.h"
#include "auto/tl/ton_api.h"
namespace ton::validatorsession {
td::Result<td::BufferSlice> serialize_candidate(const tl_object_ptr<ton_api::validatorSession_candidate> &block,
bool compression_enabled);
td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data,
bool compression_enabled,
int max_decompressed_data_size);
} // namespace ton::validatorsession

View file

@ -376,6 +376,15 @@ class ValidatorSessionRoundState : public ValidatorSessionDescription::RootObjec
void dump(ValidatorSessionDescription& desc, td::StringBuilder& sb, td::uint32 att) const;
void dump_cur_attempt(ValidatorSessionDescription& desc, td::StringBuilder& sb) const;
void for_each_sent_block(std::function<void(const SessionBlockCandidate*)> foo) const {
if (!sent_blocks_) {
return;
}
for (td::uint32 i = 0; i < sent_blocks_->size(); ++i) {
foo(sent_blocks_->at(i));
}
}
private:
const SentBlock* precommitted_block_;
const td::uint32 seqno_;
@ -516,6 +525,19 @@ class ValidatorSessionState : public ValidatorSessionDescription::RootObject {
cur_round_->dump_cur_attempt(desc, sb);
}
void for_each_cur_round_sent_block(std::function<void(const SessionBlockCandidate*)> foo) const {
cur_round_->for_each_sent_block(std::move(foo));
}
const SentBlock* get_cur_round_precommitted_block() const {
bool found;
return cur_round_->get_precommitted_block(found);
}
const CntVector<const SessionBlockCandidateSignature*>* get_cur_round_signatures() const {
return cur_round_->get_signatures();
}
static const ValidatorSessionState* make_one(ValidatorSessionDescription& desc, const ValidatorSessionState* state,
td::uint32 src_idx, td::uint32 att, bool& made);
static const ValidatorSessionState* make_all(ValidatorSessionDescription& desc, const ValidatorSessionState* state,

View file

@ -19,6 +19,7 @@
#include "validator-session.hpp"
#include "td/utils/Random.h"
#include "td/utils/crypto.h"
#include "candidate-serializer.h"
#include "ton/ton-tl.hpp"
namespace ton {
@ -222,7 +223,9 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
// Note: src is not necessarily equal to the sender of this message:
// If requested using get_broadcast_p2p, src is the creator of the block, sender possibly is some other node.
auto src_idx = description().get_source_idx(src);
auto R = fetch_tl_object<ton_api::validatorSession_candidate>(data.clone(), true);
auto R =
deserialize_candidate(data, compress_block_candidates_,
description().opts().max_block_size + description().opts().max_collated_data_size + 1024);
if (R.is_error()) {
VLOG(VALIDATOR_SESSION_WARNING) << this << "[node " << src << "][broadcast " << sha256_bits256(data.as_slice())
<< "]: failed to parse: " << R.move_as_error();
@ -344,17 +347,17 @@ void ValidatorSessionImpl::process_query(PublicKeyHash src, td::BufferSlice data
}
CHECK(block);
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), src = f->id_->src_, round_id](td::Result<BlockCandidate> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("failed to get candidate: "));
} else {
auto c = R.move_as_ok();
auto obj = create_tl_object<ton_api::validatorSession_candidate>(
src, round_id, c.id.root_hash, std::move(c.data), std::move(c.collated_data));
promise.set_value(serialize_tl_object(obj, true));
}
});
auto P = td::PromiseCreator::lambda([promise = std::move(promise), src = f->id_->src_, round_id,
compress = compress_block_candidates_](td::Result<BlockCandidate> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("failed to get candidate: "));
} else {
auto c = R.move_as_ok();
auto obj = create_tl_object<ton_api::validatorSession_candidate>(src, round_id, c.id.root_hash, std::move(c.data),
std::move(c.collated_data));
promise.set_result(serialize_candidate(obj, compress));
}
});
callback_->get_approved_candidate(description().get_source_public_key(block->get_src_idx()), f->id_->root_hash_,
f->id_->file_hash_, f->id_->collated_data_file_hash_, std::move(P));
@ -432,7 +435,7 @@ void ValidatorSessionImpl::generated_block(td::uint32 round, ValidatorSessionCan
auto b = create_tl_object<ton_api::validatorSession_candidate>(local_id().tl(), round, root_hash, std::move(data),
std::move(collated_data));
auto B = serialize_tl_object(b, true);
auto B = serialize_candidate(b, compress_block_candidates_).move_as_ok();
auto block_id = description().candidate_id(local_idx(), root_hash, file_hash, collated_data_file_hash);
@ -863,7 +866,8 @@ void ValidatorSessionImpl::on_catchain_started() {
if (x) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), round = virtual_state_->cur_round_seqno(),
src = description().get_source_id(x->get_src_idx()),
root_hash = x->get_root_hash()](td::Result<BlockCandidate> R) {
root_hash = x->get_root_hash(),
compress = compress_block_candidates_](td::Result<BlockCandidate> R) {
if (R.is_error()) {
LOG(ERROR) << "failed to get candidate: " << R.move_as_error();
} else {
@ -871,7 +875,7 @@ void ValidatorSessionImpl::on_catchain_started() {
auto broadcast = create_tl_object<ton_api::validatorSession_candidate>(
src.tl(), round, root_hash, std::move(B.data), std::move(B.collated_data));
td::actor::send_closure(SelfId, &ValidatorSessionImpl::process_broadcast, src,
serialize_tl_object(broadcast, true), td::optional<ValidatorSessionCandidateId>(),
serialize_candidate(broadcast, compress).move_as_ok(), td::optional<ValidatorSessionCandidateId>(),
false);
}
});
@ -899,6 +903,7 @@ ValidatorSessionImpl::ValidatorSessionImpl(catchain::CatChainSessionId session_i
, rldp_(rldp)
, overlay_manager_(overlays)
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync) {
compress_block_candidates_ = opts.proto_version >= 3;
description_ = ValidatorSessionDescription::create(std::move(opts), nodes, local_id);
src_round_candidate_.resize(description_->get_total_nodes());
}
@ -930,6 +935,53 @@ void ValidatorSessionImpl::get_current_stats(td::Promise<ValidatorSessionStats>
promise.set_result(std::move(stats));
}
void ValidatorSessionImpl::get_validator_group_info_for_litequery(
td::uint32 cur_round,
td::Promise<std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>>> promise) {
if (cur_round != cur_round_ || real_state_->cur_round_seqno() != cur_round) {
promise.set_value({});
return;
}
std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>> result;
real_state_->for_each_cur_round_sent_block([&](const SessionBlockCandidate *block) {
if (block->get_block() == nullptr) {
return;
}
auto candidate = create_tl_object<lite_api::liteServer_nonfinal_candidateInfo>();
candidate->id_ = create_tl_object<lite_api::liteServer_nonfinal_candidateId>();
candidate->id_->block_id_ = create_tl_object<lite_api::tonNode_blockIdExt>();
candidate->id_->block_id_->root_hash_ =
block->get_block()->get_root_hash(); // other fields will be filled in validator-group.cpp
candidate->id_->block_id_->file_hash_ = block->get_block()->get_file_hash();
candidate->id_->creator_ =
description().get_source_public_key(block->get_block()->get_src_idx()).ed25519_value().raw();
candidate->id_->collated_data_hash_ = block->get_block()->get_collated_data_file_hash();
candidate->total_weight_ = description().get_total_weight();
candidate->approved_weight_ = 0;
candidate->signed_weight_ = 0;
for (td::uint32 i = 0; i < description().get_total_nodes(); ++i) {
if (real_state_->check_block_is_approved_by(description(), i, block->get_id())) {
candidate->approved_weight_ += description().get_node_weight(i);
}
}
auto precommited = real_state_->get_cur_round_precommitted_block();
if (SentBlock::get_block_id(precommited) == SentBlock::get_block_id(block->get_block())) {
auto signatures = real_state_->get_cur_round_signatures();
if (signatures) {
for (td::uint32 i = 0; i < description().get_total_nodes(); ++i) {
if (signatures->at(i)) {
candidate->signed_weight_ += description().get_node_weight(i);
}
}
}
}
result.push_back(std::move(candidate));
});
promise.set_result(std::move(result));
}
void ValidatorSessionImpl::start_up() {
CHECK(!rldp_.empty());
cur_round_ = 0;

View file

@ -28,6 +28,7 @@
#include "catchain/catchain-types.h"
#include "validator-session-types.h"
#include "auto/tl/lite_api.h"
namespace ton {
@ -92,6 +93,9 @@ class ValidatorSession : public td::actor::Actor {
virtual void start() = 0;
virtual void destroy() = 0;
virtual void get_current_stats(td::Promise<ValidatorSessionStats> promise) = 0;
virtual void get_validator_group_info_for_litequery(
td::uint32 cur_round,
td::Promise<std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>>> promise) = 0;
virtual void get_session_info(td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise) = 0;

View file

@ -156,6 +156,7 @@ class ValidatorSessionImpl : public ValidatorSession {
bool started_ = false;
bool catchain_started_ = false;
bool allow_unsafe_self_blocks_resync_;
bool compress_block_candidates_ = false;
ValidatorSessionStats cur_stats_;
void stats_init();
@ -177,6 +178,9 @@ class ValidatorSessionImpl : public ValidatorSession {
void start() override;
void destroy() override;
void get_current_stats(td::Promise<ValidatorSessionStats> promise) override;
void get_validator_group_info_for_litequery(
td::uint32 cur_round,
td::Promise<std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>>> promise) override;
void process_blocks(std::vector<catchain::CatChainBlock *> blocks);
void finished_processing();

View file

@ -149,6 +149,8 @@ set(FULL_NODE_SOURCE
full-node-master.cpp
full-node-private-overlay.hpp
full-node-private-overlay.cpp
full-node-serializer.hpp
full-node-serializer.cpp
full-node-private-overlay-v2.hpp
full-node-private-overlay-v2.cpp

View file

@ -371,7 +371,8 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
td::Promise<td::BufferSlice> promise) {
promise.set_value(create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version(), proto_capabilities()));
promise.set_value(
create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version_major(), proto_version_minor(), 0));
}
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,

View file

@ -28,10 +28,10 @@ namespace fullnode {
class FullNodeMasterImpl : public FullNodeMaster {
public:
static constexpr td::uint32 proto_version() {
static constexpr td::uint32 proto_version_major() {
return 1;
}
static constexpr td::uint64 proto_capabilities() {
static constexpr td::uint32 proto_version_minor() {
return 0;
}
void start_up() override;

View file

@ -14,11 +14,10 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "full-node-private-overlay.hpp"
#include "ton/ton-tl.hpp"
#include "common/delay.h"
#include "full-node-serializer.hpp"
namespace ton {
@ -26,20 +25,20 @@ namespace validator {
namespace fullnode {
void FullNodePrivateOverlay::process_broadcast(PublicKeyHash, ton_api::tonNode_blockBroadcast &query) {
std::vector<BlockSignature> signatures;
for (auto &sig : query.signatures_) {
signatures.emplace_back(BlockSignature{sig->who_, std::move(sig->signature_)});
void FullNodePrivateOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
process_block_broadcast(src, query);
}
void FullNodePrivateOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query) {
process_block_broadcast(src, query);
}
void FullNodePrivateOverlay::process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
auto B = deserialize_block_broadcast(query, overlay::Overlays::max_fec_broadcast_size());
if (B.is_error()) {
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
return;
}
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) {
if (R.is_error()) {
if (R.error().code() == ErrorCode::notready) {
@ -49,7 +48,7 @@ void FullNodePrivateOverlay::process_broadcast(PublicKeyHash, ton_api::tonNode_b
}
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, std::move(B),
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, B.move_as_ok(),
std::move(P));
}
@ -87,15 +86,13 @@ void FullNodePrivateOverlay::send_broadcast(BlockBroadcast broadcast) {
if (!inited_) {
return;
}
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 = serialize_block_broadcast(broadcast, false); // compression_enabled = false
if (B.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to serialize block broadcast: " << B.move_as_error();
return;
}
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, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
}
void FullNodePrivateOverlay::start_up() {

View file

@ -27,6 +27,9 @@ namespace fullnode {
class FullNodePrivateOverlay : public td::actor::Actor {
public:
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query);
void process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query);
template <class T>
void process_broadcast(PublicKeyHash, T &) {

View file

@ -0,0 +1,155 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "full-node-serializer.hpp"
#include "ton/ton-tl.hpp"
#include "tl-utils/common-utils.hpp"
#include "auto/tl/ton_api.hpp"
#include "tl-utils/tl-utils.hpp"
#include "vm/boc.h"
#include "td/utils/lz4.h"
#include "full-node.h"
#include "td/utils/overloaded.h"
namespace ton::validator::fullnode {
td::Result<td::BufferSlice> serialize_block_broadcast(const BlockBroadcast& broadcast, bool compression_enabled) {
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()));
}
if (!compression_enabled) {
return 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());
}
TRY_RESULT(proof_root, vm::std_boc_deserialize(broadcast.proof));
TRY_RESULT(data_root, vm::std_boc_deserialize(broadcast.data));
TRY_RESULT(boc, vm::std_boc_serialize_multi({proof_root, data_root}, 2));
td::BufferSlice data =
create_serialize_tl_object<ton_api::tonNode_blockBroadcastCompressed_data>(std::move(sigs), std::move(boc));
td::BufferSlice compressed = td::lz4_compress(data);
VLOG(FULL_NODE_DEBUG) << "Compressing block broadcast: "
<< broadcast.data.size() + broadcast.proof.size() + broadcast.signatures.size() * 96 << " -> "
<< compressed.size();
return create_serialize_tl_object<ton_api::tonNode_blockBroadcastCompressed>(
create_tl_block_id(broadcast.block_id), broadcast.catchain_seqno, broadcast.validator_set_hash, 0,
std::move(compressed));
}
static td::Result<BlockBroadcast> deserialize_block_broadcast(ton_api::tonNode_blockBroadcast& f) {
std::vector<BlockSignature> signatures;
for (auto& sig : f.signatures_) {
signatures.emplace_back(BlockSignature{sig->who_, std::move(sig->signature_)});
}
return BlockBroadcast{create_block_id(f.id_),
std::move(signatures),
static_cast<UnixTime>(f.catchain_seqno_),
static_cast<td::uint32>(f.validator_set_hash_),
std::move(f.data_),
std::move(f.proof_)};
}
static td::Result<BlockBroadcast> deserialize_block_broadcast(ton_api::tonNode_blockBroadcastCompressed& f,
int max_decompressed_size) {
TRY_RESULT(decompressed, td::lz4_decompress(f.compressed_, max_decompressed_size));
TRY_RESULT(f2, fetch_tl_object<ton_api::tonNode_blockBroadcastCompressed_data>(decompressed, true));
std::vector<BlockSignature> signatures;
for (auto& sig : f2->signatures_) {
signatures.emplace_back(BlockSignature{sig->who_, std::move(sig->signature_)});
}
TRY_RESULT(roots, vm::std_boc_deserialize_multi(f2->proof_data_, 2));
if (roots.size() != 2) {
return td::Status::Error("expected 2 roots in boc");
}
TRY_RESULT(proof, vm::std_boc_serialize(roots[0], 0));
TRY_RESULT(data, vm::std_boc_serialize(roots[1], 31));
VLOG(FULL_NODE_DEBUG) << "Decompressing block broadcast: " << f.compressed_.size() << " -> "
<< data.size() + proof.size() + signatures.size() * 96;
return BlockBroadcast{create_block_id(f.id_),
std::move(signatures),
static_cast<UnixTime>(f.catchain_seqno_),
static_cast<td::uint32>(f.validator_set_hash_),
std::move(data),
std::move(proof)};
}
td::Result<BlockBroadcast> deserialize_block_broadcast(ton_api::tonNode_Broadcast& obj,
int max_decompressed_data_size) {
td::Result<BlockBroadcast> B;
ton_api::downcast_call(obj,
td::overloaded([&](ton_api::tonNode_blockBroadcast& f) { B = deserialize_block_broadcast(f); },
[&](ton_api::tonNode_blockBroadcastCompressed& f) {
B = deserialize_block_broadcast(f, max_decompressed_data_size);
},
[&](auto&) { B = td::Status::Error("unknown broadcast type"); }));
return B;
}
td::Result<td::BufferSlice> serialize_block_full(const BlockIdExt& id, td::Slice proof, td::Slice data,
bool is_proof_link, bool compression_enabled) {
if (!compression_enabled) {
return create_serialize_tl_object<ton_api::tonNode_dataFull>(create_tl_block_id(id), td::BufferSlice(proof),
td::BufferSlice(data), is_proof_link);
}
TRY_RESULT(proof_root, vm::std_boc_deserialize(proof));
TRY_RESULT(data_root, vm::std_boc_deserialize(data));
TRY_RESULT(boc, vm::std_boc_serialize_multi({proof_root, data_root}, 2));
td::BufferSlice compressed = td::lz4_compress(boc);
VLOG(FULL_NODE_DEBUG) << "Compressing block full: " << data.size() + proof.size() << " -> " << compressed.size();
return create_serialize_tl_object<ton_api::tonNode_dataFullCompressed>(create_tl_block_id(id), 0,
std::move(compressed), is_proof_link);
}
static td::Status deserialize_block_full(ton_api::tonNode_dataFull& f, BlockIdExt& id, td::BufferSlice& proof,
td::BufferSlice& data, bool& is_proof_link) {
id = create_block_id(f.id_);
proof = std::move(f.proof_);
data = std::move(f.block_);
is_proof_link = f.is_link_;
return td::Status::OK();
}
static td::Status deserialize_block_full(ton_api::tonNode_dataFullCompressed& f, BlockIdExt& id, td::BufferSlice& proof,
td::BufferSlice& data, bool& is_proof_link, int max_decompressed_size) {
TRY_RESULT(decompressed, td::lz4_decompress(f.compressed_, max_decompressed_size));
TRY_RESULT(roots, vm::std_boc_deserialize_multi(decompressed, 2));
if (roots.size() != 2) {
return td::Status::Error("expected 2 roots in boc");
}
TRY_RESULT_ASSIGN(proof, vm::std_boc_serialize(roots[0], 0));
TRY_RESULT_ASSIGN(data, vm::std_boc_serialize(roots[1], 31));
VLOG(FULL_NODE_DEBUG) << "Decompressing block full: " << f.compressed_.size() << " -> " << data.size() + proof.size();
id = create_block_id(f.id_);
is_proof_link = f.is_link_;
return td::Status::OK();
}
td::Status deserialize_block_full(ton_api::tonNode_DataFull& obj, BlockIdExt& id, td::BufferSlice& proof,
td::BufferSlice& data, bool& is_proof_link, int max_decompressed_data_size) {
td::Status S;
ton_api::downcast_call(
obj, td::overloaded(
[&](ton_api::tonNode_dataFull& f) { S = deserialize_block_full(f, id, proof, data, is_proof_link); },
[&](ton_api::tonNode_dataFullCompressed& f) {
S = deserialize_block_full(f, id, proof, data, is_proof_link, max_decompressed_data_size);
},
[&](auto&) { S = td::Status::Error("unknown data type"); }));
return S;
}
} // namespace ton::validator::fullnode

View file

@ -0,0 +1,31 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ton/ton-types.h"
#include "auto/tl/ton_api.h"
namespace ton::validator::fullnode {
td::Result<td::BufferSlice> serialize_block_broadcast(const BlockBroadcast& broadcast, bool compression_enabled);
td::Result<BlockBroadcast> deserialize_block_broadcast(ton_api::tonNode_Broadcast& obj, int max_decompressed_data_size);
td::Result<td::BufferSlice> serialize_block_full(const BlockIdExt& id, td::Slice proof, td::Slice data,
bool is_proof_link, bool compression_enabled);
td::Status deserialize_block_full(ton_api::tonNode_DataFull& obj, BlockIdExt& id, td::BufferSlice& proof,
td::BufferSlice& data, bool& is_proof_link, int max_decompressed_data_size);
} // namespace ton::validator::fullnode

View file

@ -20,6 +20,7 @@
#include "validator/validator.h"
#include "ton/ton-tl.hpp"
#include "full-node-serializer.hpp"
namespace ton {
@ -38,8 +39,8 @@ class BlockFullSender : public td::actor::Actor {
stop();
}
void finish_query() {
promise_.set_value(create_serialize_tl_object<ton_api::tonNode_dataFull>(
create_tl_block_id(block_id_), std::move(proof_), std::move(data_), is_proof_link_));
promise_.set_result(
serialize_block_full(block_id_, proof_, data_, is_proof_link_, false)); // compression_enabled = false
stop();
}
void start_up() override {

View file

@ -22,6 +22,7 @@
#include "td/utils/overloaded.h"
#include "full-node-shard.hpp"
#include "full-node-shard-queries.hpp"
#include "full-node-serializer.hpp"
#include "ton/ton-shard.h"
#include "ton/ton-tl.hpp"
@ -739,24 +740,24 @@ void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_ne
}
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
BlockIdExt block_id = create_block_id(query.id_);
process_block_broadcast(src, query);
}
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query) {
process_block_broadcast(src, query);
}
void FullNodeShardImpl::process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
auto B = deserialize_block_broadcast(query, overlay::Overlays::max_fec_broadcast_size());
if (B.is_error()) {
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
return;
}
//if (!shard_is_ancestor(shard_, block_id.shard_full())) {
// LOG(FULL_NODE_WARNING) << "dropping block broadcast: shard mismatch. overlay=" << shard_.to_str()
// << " block=" << block_id.to_str();
// return;
//}
std::vector<BlockSignature> signatures;
for (auto &sig : query.signatures_) {
signatures.emplace_back(BlockSignature{sig->who_, std::move(sig->signature_)});
}
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) {
if (R.is_error()) {
if (R.error().code() == ErrorCode::notready) {
@ -766,7 +767,7 @@ void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_bl
}
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, std::move(B),
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, B.move_as_ok(),
std::move(P));
}
@ -851,15 +852,13 @@ void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) {
UNREACHABLE();
return;
}
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 = serialize_block_broadcast(broadcast, false); // compression_enabled = false
if (B.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to serialize block broadcast: " << B.move_as_error();
return;
}
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));
overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
}
void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,

View file

@ -161,6 +161,9 @@ class FullNodeShardImpl : public FullNodeShard {
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query);
void process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &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);

View file

@ -7,6 +7,7 @@ endif()
set(TON_VALIDATOR_SOURCE
accept-block.cpp
block.cpp
candidates-buffer.cpp
check-proof.cpp
collator.cpp
config.cpp
@ -25,6 +26,7 @@ set(TON_VALIDATOR_SOURCE
accept-block.hpp
block.hpp
candidates-buffer.hpp
check-proof.hpp
collator-impl.h
collator.h

View file

@ -0,0 +1,213 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "candidates-buffer.hpp"
#include "fabric.h"
namespace ton::validator {
void CandidatesBuffer::start_up() {
alarm_timestamp() = td::Timestamp::in(60.0);
}
void CandidatesBuffer::alarm() {
alarm_timestamp() = td::Timestamp::in(60.0);
for (auto it = candidates_.begin(); it != candidates_.end();) {
Candidate &entry = it->second;
if (entry.ttl_.is_in_past()) {
for (auto &p : entry.data_waiters_) {
p.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
}
for (auto &p : entry.state_waiters_) {
p.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
}
it = candidates_.erase(it);
} else {
++it;
}
}
}
void CandidatesBuffer::add_new_candidate(BlockIdExt id, PublicKey source, FileHash collated_data_file_hash) {
auto it = candidates_.emplace(id, Candidate{});
Candidate &entry = it.first->second;
entry.ttl_ = td::Timestamp::in(120.0);
if (!it.second) { // not inserted
return;
}
LOG(DEBUG) << "New block candidate " << id.to_str();
entry.source_ = source;
entry.collated_data_file_hash_ = collated_data_file_hash;
}
void CandidatesBuffer::get_block_data(BlockIdExt id, td::Promise<td::Ref<BlockData>> promise) {
auto it = candidates_.find(id);
if (it == candidates_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "unknown block candidate"));
return;
}
Candidate &entry = it->second;
if (entry.data_.not_null()) {
promise.set_result(entry.data_);
return;
}
entry.data_waiters_.push_back(std::move(promise));
if (entry.data_requested_) {
return;
}
entry.data_requested_ = true;
td::actor::send_closure(manager_, &ValidatorManager::get_block_candidate_from_db, entry.source_, id,
entry.collated_data_file_hash_, [SelfId = actor_id(this), id](td::Result<BlockCandidate> R) {
td::actor::send_closure(SelfId, &CandidatesBuffer::got_block_candidate, id, std::move(R));
});
}
void CandidatesBuffer::got_block_candidate(BlockIdExt id, td::Result<BlockCandidate> R) {
if (R.is_error()) {
finish_get_block_data(id, R.move_as_error());
return;
}
BlockCandidate cand = R.move_as_ok();
CHECK(cand.id == id);
finish_get_block_data(id, create_block(id, std::move(cand.data)));
}
void CandidatesBuffer::get_block_state(BlockIdExt id, td::Promise<td::Ref<ShardState>> promise) {
auto it = candidates_.find(id);
if (it == candidates_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "unknown block candidate"));
return;
}
Candidate &entry = it->second;
if (entry.state_.not_null()) {
promise.set_result(entry.state_);
return;
}
entry.state_waiters_.push_back(std::move(promise));
if (entry.state_requested_) {
return;
}
entry.state_requested_ = true;
get_block_data(id, [SelfId = actor_id(this), id](td::Result<td::Ref<BlockData>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &CandidatesBuffer::finish_get_block_state, id, R.move_as_error());
return;
}
td::actor::send_closure(SelfId, &CandidatesBuffer::get_block_state_cont, id, R.move_as_ok());
});
}
void CandidatesBuffer::get_block_state_cont(BlockIdExt id, td::Ref<BlockData> data) {
CHECK(id == data->block_id());
std::vector<BlockIdExt> prev;
BlockIdExt mc_blkid;
bool after_split;
auto S = block::unpack_block_prev_blk_ext(data->root_cell(), id, prev, mc_blkid, after_split);
if (S.is_error()) {
finish_get_block_state(id, std::move(S));
return;
}
get_block_state_cont2(std::move(data), std::move(prev), {});
}
void CandidatesBuffer::get_block_state_cont2(td::Ref<BlockData> block, std::vector<BlockIdExt> prev,
std::vector<td::Ref<ShardState>> prev_states) {
if (prev_states.size() < prev.size()) {
BlockIdExt prev_id = prev[prev_states.size()];
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db_short, prev_id,
[SelfId = actor_id(this), block = std::move(block), prev = std::move(prev),
prev_states = std::move(prev_states)](td::Result<td::Ref<ShardState>> R) mutable {
if (R.is_error()) {
td::actor::send_closure(SelfId, &CandidatesBuffer::finish_get_block_state,
block->block_id(), R.move_as_error());
return;
}
prev_states.push_back(R.move_as_ok());
td::actor::send_closure(SelfId, &CandidatesBuffer::get_block_state_cont2,
std::move(block), std::move(prev), std::move(prev_states));
});
return;
}
BlockIdExt id = block->block_id();
td::Ref<ShardState> state;
CHECK(prev_states.size() == 1 || prev_states.size() == 2);
if (prev_states.size() == 2) { // after merge
auto R = prev_states[0]->merge_with(*prev_states[1]);
if (R.is_error()) {
finish_get_block_state(id, R.move_as_error());
return;
}
state = R.move_as_ok();
} else if (id.shard_full() != prev[0].shard_full()) { // after split
auto R = prev_states[0]->split();
if (R.is_error()) {
finish_get_block_state(id, R.move_as_error());
return;
}
auto s = R.move_as_ok();
state = is_left_child(id.shard_full()) ? std::move(s.first) : std::move(s.second);
} else { // no split/merge
state = std::move(prev_states[0]);
}
auto S = state.write().apply_block(id, std::move(block));
if (S.is_error()) {
finish_get_block_state(id, std::move(S));
return;
}
finish_get_block_state(id, std::move(state));
}
void CandidatesBuffer::finish_get_block_data(BlockIdExt id, td::Result<td::Ref<BlockData>> res) {
auto it = candidates_.find(id);
if (it == candidates_.end()) {
return;
}
Candidate &entry = it->second;
for (auto &p : entry.data_waiters_) {
p.set_result(res.clone());
}
entry.data_waiters_.clear();
entry.data_requested_ = false;
if (res.is_ok()) {
entry.data_ = res.move_as_ok();
LOG(DEBUG) << "Loaded block data for " << id.to_str();
} else {
LOG(DEBUG) << "Failed to load block data for " << id.to_str() << ": " << res.move_as_error();
}
}
void CandidatesBuffer::finish_get_block_state(BlockIdExt id, td::Result<td::Ref<ShardState>> res) {
auto it = candidates_.find(id);
if (it == candidates_.end()) {
return;
}
Candidate &entry = it->second;
for (auto &p : entry.state_waiters_) {
p.set_result(res.clone());
}
entry.state_waiters_.clear();
entry.state_requested_ = false;
if (res.is_ok()) {
entry.state_ = res.move_as_ok();
LOG(DEBUG) << "Loaded block state for " << id.to_str();
} else {
LOG(DEBUG) << "Failed to load block state for " << id.to_str() << ": " << res.move_as_error();
}
}
} // namespace ton::validator

View 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/>.
*/
#pragma once
#include "ton/ton-types.h"
#include "td/actor/actor.h"
#include "interfaces/validator-manager.h"
namespace ton::validator {
class CandidatesBuffer : public td::actor::Actor {
public:
explicit CandidatesBuffer(td::actor::ActorId<ValidatorManager> manager) : manager_(std::move(manager)) {
}
void start_up() override;
void alarm() override;
void add_new_candidate(BlockIdExt id, PublicKey source, FileHash collated_data_file_hash);
void get_block_data(BlockIdExt id, td::Promise<td::Ref<BlockData>> promise);
void get_block_state(BlockIdExt id, td::Promise<td::Ref<ShardState>> promise);
private:
td::actor::ActorId<ValidatorManager> manager_;
struct Candidate {
PublicKey source_;
FileHash collated_data_file_hash_;
td::Timestamp ttl_;
td::Ref<BlockData> data_;
std::vector<td::Promise<td::Ref<BlockData>>> data_waiters_;
bool data_requested_{false};
td::Ref<ShardState> state_;
std::vector<td::Promise<td::Ref<ShardState>>> state_waiters_;
bool state_requested_{false};
};
std::map<BlockIdExt, Candidate> candidates_;
void got_block_candidate(BlockIdExt id, td::Result<BlockCandidate> R);
void get_block_state_cont(BlockIdExt id, td::Ref<BlockData> data);
void get_block_state_cont2(td::Ref<BlockData> block, std::vector<BlockIdExt> prev,
std::vector<td::Ref<ShardState>> prev_states);
void finish_get_block_data(BlockIdExt id, td::Result<td::Ref<BlockData>> res);
void finish_get_block_state(BlockIdExt id, td::Result<td::Ref<ShardState>> res);
};
} // namespace ton::validator

View file

@ -336,6 +336,9 @@ class Collator final : public td::actor::Actor {
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);
public:
static td::uint32 get_skip_externals_queue_size();
};
} // namespace validator

View file

@ -5352,6 +5352,10 @@ void Collator::after_get_external_messages(td::Result<std::vector<Ref<ExtMessage
check_pending();
}
td::uint32 Collator::get_skip_externals_queue_size() {
return SKIP_EXTERNALS_QUEUE_SIZE;
}
} // namespace validator
} // namespace ton

View file

@ -42,6 +42,8 @@
#include "signature-set.hpp"
#include "fabric.h"
#include <ctime>
#include "td/actor/MultiPromise.h"
#include "collator-impl.h"
namespace ton {
@ -275,6 +277,16 @@ void LiteQuery::perform() {
[&](lite_api::liteServer_getShardBlockProof& q) {
this->perform_getShardBlockProof(create_block_id(q.id_));
},
[&](lite_api::liteServer_nonfinal_getCandidate& q) {
this->perform_nonfinal_getCandidate(q.id_->creator_, create_block_id(q.id_->block_id_),
q.id_->collated_data_hash_);
},
[&](lite_api::liteServer_nonfinal_getValidatorGroups& q) {
this->perform_nonfinal_getValidatorGroups(q.mode_, ShardIdFull{q.wc_, (ShardId)q.shard_});
},
[&](lite_api::liteServer_getOutMsgQueueSizes& q) {
this->perform_getOutMsgQueueSizes(q.mode_ & 1 ? ShardIdFull(q.wc_, q.shard_) : td::optional<ShardIdFull>());
},
[&](auto& obj) { this->abort_query(td::Status::Error(ErrorCode::protoviolation, "unknown query")); }));
}
@ -343,21 +355,15 @@ void LiteQuery::perform_getBlock(BlockIdExt blkid) {
fatal_error("invalid BlockIdExt");
return;
}
get_block_handle_checked(blkid, [manager = manager_, Self = actor_id(this), blkid](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db, R.move_as_ok(),
[=](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlock, blkid,
res.move_as_ok());
}
});
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_for_litequery, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlock, blkid,
res.move_as_ok());
}
});
}
void LiteQuery::continue_getBlock(BlockIdExt blkid, Ref<ton::validator::BlockData> block) {
@ -375,21 +381,15 @@ void LiteQuery::perform_getBlockHeader(BlockIdExt blkid, int mode) {
fatal_error("invalid BlockIdExt");
return;
}
get_block_handle_checked(blkid, [=, manager = manager_, Self = actor_id(this)](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db, R.move_as_ok(),
[=](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockHeader, blkid,
mode, res.move_as_ok());
}
});
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_for_litequery, blkid,
[Self = actor_id(this), blkid, mode](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockHeader, blkid, mode,
res.move_as_ok());
}
});
}
static bool visit(Ref<vm::Cell> cell);
@ -495,33 +495,27 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
fatal_error("cannot request total state: possibly too large");
return;
}
get_block_handle_checked(blkid, [=, manager = manager_, Self = actor_id(this)](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
if (blkid.id.seqno) {
td::actor::send_closure_later(manager, &ValidatorManager::get_shard_state_from_db, R.move_as_ok(),
[=](td::Result<Ref<ton::validator::ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getState, blkid,
res.move_as_ok());
}
});
} else {
td::actor::send_closure_later(manager, &ValidatorManager::get_zero_state, blkid,
[=](td::Result<td::BufferSlice> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getZeroState, blkid,
res.move_as_ok());
}
});
}
});
if (blkid.id.seqno) {
td::actor::send_closure(manager_, &ValidatorManager::get_block_state_for_litequery, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getState, blkid,
res.move_as_ok());
}
});
} else {
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getZeroState, blkid,
res.move_as_ok());
}
});
}
}
void LiteQuery::continue_getState(BlockIdExt blkid, Ref<ton::validator::ShardState> state) {
@ -583,7 +577,7 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
base_blk_id_ = blkid;
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
manager_, &ValidatorManager::get_block_data_for_litequery, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
@ -641,7 +635,7 @@ bool LiteQuery::request_mc_block_state(BlockIdExt blkid) {
base_blk_id_ = blkid;
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
manager_, &ValidatorManager::get_block_state_for_litequery, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
@ -671,22 +665,16 @@ bool LiteQuery::request_block_state(BlockIdExt blkid) {
}
blk_id_ = blkid;
++pending_;
get_block_handle_checked(blkid, [=, manager = manager_, Self = actor_id(this)](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
td::actor::send_closure_later(
manager, &ValidatorManager::get_shard_state_from_db, R.move_as_ok(),
[=](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
} else {
td::actor::send_closure_later(Self, &LiteQuery::got_block_state, blkid, res.move_as_ok());
}
});
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_state_for_litequery, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(
Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
} else {
td::actor::send_closure_later(Self, &LiteQuery::got_block_state, blkid, res.move_as_ok());
}
});
return true;
}
@ -699,22 +687,16 @@ bool LiteQuery::request_block_data(BlockIdExt blkid) {
}
blk_id_ = blkid;
++pending_;
get_block_handle_checked(blkid, [=, manager = manager_, Self = actor_id(this)](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
td::actor::send_closure_later(
manager, &ValidatorManager::get_block_data_from_db, R.move_as_ok(),
[=](td::Result<Ref<BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
} else {
td::actor::send_closure_later(Self, &LiteQuery::got_block_data, blkid, res.move_as_ok());
}
});
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_for_litequery, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(
Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
} else {
td::actor::send_closure_later(Self, &LiteQuery::got_block_data, blkid, res.move_as_ok());
}
});
return true;
}
@ -1712,7 +1694,7 @@ void LiteQuery::continue_getTransactions(unsigned remaining, bool exact) {
LOG(DEBUG) << "sending get_block_by_lt_from_db() query to manager for " << acc_workchain_ << ":" << acc_addr_.to_hex()
<< " " << trans_lt_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_by_lt_from_db_for_litequery, ton::extract_addr_prefix(acc_workchain_, acc_addr_),
manager_, &ValidatorManager::get_block_by_lt_for_litequery, ton::extract_addr_prefix(acc_workchain_, acc_addr_),
trans_lt_, [Self = actor_id(this), remaining, manager = manager_](td::Result<ConstBlockHandle> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{});
@ -2088,11 +2070,13 @@ void LiteQuery::perform_lookupBlockWithProof(BlockId blkid, BlockIdExt mc_blkid,
});
if (mode & 2) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_lt_from_db_for_litequery, pfx, lt, std::move(P));
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_lt_for_litequery, pfx, lt, std::move(P));
} else if (mode & 4) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_unix_time_from_db_for_litequery, pfx, utime, std::move(P));
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_unix_time_for_litequery, pfx, utime,
std::move(P));
} else {
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_seqno_from_db_for_litequery, pfx, blkid.seqno, std::move(P));
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_seqno_for_litequery, pfx, blkid.seqno,
std::move(P));
}
}
@ -2368,13 +2352,13 @@ void LiteQuery::perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, Uni
ton::AccountIdPrefixFull pfx{blkid.workchain, blkid.shard};
if (mode & 2) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_lt_from_db_for_litequery, pfx, lt,
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_lt_for_litequery, pfx, lt,
std::move(P));
} else if (mode & 4) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_unix_time_from_db_for_litequery, pfx, utime,
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_unix_time_for_litequery, pfx, utime,
std::move(P));
} else {
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_seqno_from_db_for_litequery, pfx,
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_seqno_for_litequery, pfx,
blkid.seqno, std::move(P));
}
}
@ -3133,7 +3117,7 @@ void LiteQuery::perform_getShardBlockProof(BlockIdExt blkid) {
}
AccountIdPrefixFull pfx{masterchainId, shardIdAll};
td::actor::send_closure_later(
manager, &ValidatorManager::get_block_by_seqno_from_db_for_litequery, pfx, handle->masterchain_ref_block(),
manager, &ValidatorManager::get_block_by_seqno_for_litequery, pfx, handle->masterchain_ref_block(),
[Self, manager](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
@ -3237,5 +3221,92 @@ void LiteQuery::continue_getShardBlockProof(Ref<BlockData> cur_block,
});
}
void LiteQuery::perform_getOutMsgQueueSizes(td::optional<ShardIdFull> shard) {
LOG(INFO) << "started a getOutMsgQueueSizes" << (shard ? shard.value().to_str() : "") << " liteserver query";
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[Self = actor_id(this), shard](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getOutMsgQueueSizes, shard, res.ok().first);
}
});
}
void LiteQuery::continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Ref<MasterchainState> state) {
std::vector<BlockIdExt> blocks;
if (!shard || shard_intersects(shard.value(), state->get_shard())) {
blocks.push_back(state->get_block_id());
}
for (auto& x : state->get_shards()) {
if (!shard || shard_intersects(shard.value(), x->shard())) {
blocks.push_back(x->top_block_id());
}
}
auto res = std::make_shared<std::vector<tl_object_ptr<lite_api::liteServer_outMsgQueueSize>>>(blocks.size());
td::MultiPromise mp;
auto ig = mp.init_guard();
for (size_t i = 0; i < blocks.size(); ++i) {
td::actor::send_closure(manager_, &ValidatorManager::get_out_msg_queue_size, blocks[i],
[promise = ig.get_promise(), res, i, id = blocks[i]](td::Result<td::uint32> R) mutable {
TRY_RESULT_PROMISE(promise, value, std::move(R));
res->at(i) = create_tl_object<lite_api::liteServer_outMsgQueueSize>(
create_tl_lite_block_id(id), value);
promise.set_value(td::Unit());
});
}
ig.add_promise([Self = actor_id(this), res](td::Result<td::Unit> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
td::actor::send_closure(Self, &LiteQuery::finish_query,
create_serialize_tl_object<lite_api::liteServer_outMsgQueueSizes>(
std::move(*res), Collator::get_skip_externals_queue_size()),
false);
});
}
void LiteQuery::perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash) {
LOG(INFO) << "started a nonfinal.getCandidate liteserver query";
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_candidate_for_litequery, PublicKey{pubkeys::Ed25519{source}}, blkid, collated_data_hash,
[Self = actor_id(this)](td::Result<BlockCandidate> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
} else {
BlockCandidate cand = R.move_as_ok();
td::actor::send_closure_later(
Self, &LiteQuery::finish_query,
create_serialize_tl_object<lite_api::liteServer_nonfinal_candidate>(
create_tl_object<lite_api::liteServer_nonfinal_candidateId>(
create_tl_lite_block_id(cand.id), cand.pubkey.as_bits256(), cand.collated_file_hash),
std::move(cand.data), std::move(cand.collated_data)),
false);
}
});
}
void LiteQuery::perform_nonfinal_getValidatorGroups(int mode, ShardIdFull shard) {
bool with_shard = mode & 1;
LOG(INFO) << "started a nonfinal.getValidatorGroups" << (with_shard ? shard.to_str() : "(all)")
<< " liteserver query";
td::optional<ShardIdFull> maybe_shard;
if (with_shard) {
maybe_shard = shard;
}
td::actor::send_closure(
manager_, &ValidatorManager::get_validator_groups_info_for_litequery, maybe_shard,
[Self = actor_id(this)](td::Result<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::finish_query, serialize_tl_object(R.move_as_ok(), true),
false);
}
});
}
} // namespace validator
} // namespace ton

View file

@ -168,6 +168,11 @@ class LiteQuery : public td::actor::Actor {
void perform_getShardBlockProof(BlockIdExt blkid);
void continue_getShardBlockProof(Ref<BlockData> cur_block,
std::vector<std::pair<BlockIdExt, td::BufferSlice>> result);
void perform_getOutMsgQueueSizes(td::optional<ShardIdFull> shard);
void continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Ref<MasterchainState> state);
void perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash);
void perform_nonfinal_getValidatorGroups(int mode, ShardIdFull shard);
void load_prevKeyBlock(ton::BlockIdExt blkid, td::Promise<std::pair<BlockIdExt, Ref<BlockQ>>>);
void continue_loadPrevKeyBlock(ton::BlockIdExt blkid, td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res,

View file

@ -29,6 +29,7 @@
#include "liteserver.h"
#include "crypto/vm/db/DynamicBagOfCellsDb.h"
#include "validator-session/validator-session-types.h"
#include "auto/tl/lite_api.h"
#include "impl/out-msg-queue-proof.hpp"
namespace ton {
@ -171,12 +172,19 @@ class ValidatorManager : public ValidatorManagerInterface {
virtual void log_validator_session_stats(BlockIdExt block_id, validatorsession::ValidatorSessionStats stats) = 0;
virtual void get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_by_lt_from_db_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_by_unix_time_from_db_for_litequery(AccountIdPrefixFull account, UnixTime ts,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_by_seqno_from_db_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_data_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) = 0;
virtual void get_block_state_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void get_block_by_lt_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_by_unix_time_for_litequery(AccountIdPrefixFull account, UnixTime ts,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_by_seqno_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_block_candidate_for_litequery(PublicKey source, BlockIdExt block_id, FileHash collated_data_hash,
td::Promise<BlockCandidate> promise) = 0;
virtual void get_validator_groups_info_for_litequery(
td::optional<ShardIdFull> shard,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) = 0;
virtual void add_lite_query_stats(int lite_query_id) {
}

View file

@ -396,18 +396,33 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) override {
get_block_handle(block_id, false, promise.wrap([](BlockHandle &&handle) -> ConstBlockHandle { return handle; }));
}
void get_block_by_lt_from_db_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
void get_block_data_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) override {
get_block_data_from_db_short(block_id, std::move(promise));
}
void get_block_state_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override {
get_shard_state_from_db_short(block_id, std::move(promise));
}
void get_block_by_lt_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
td::Promise<ConstBlockHandle> promise) override {
get_block_by_lt_from_db(account, lt, std::move(promise));
}
void get_block_by_unix_time_from_db_for_litequery(AccountIdPrefixFull account, UnixTime ts,
void get_block_by_unix_time_for_litequery(AccountIdPrefixFull account, UnixTime ts,
td::Promise<ConstBlockHandle> promise) override {
get_block_by_unix_time_from_db(account, ts, std::move(promise));
}
void get_block_by_seqno_from_db_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
void get_block_by_seqno_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) override {
get_block_by_seqno_from_db(account, seqno, std::move(promise));
}
void get_block_candidate_for_litequery(PublicKey source, BlockIdExt block_id, FileHash collated_data_hash,
td::Promise<BlockCandidate> promise) override {
promise.set_result(td::Status::Error("not implemented"));
}
void get_validator_groups_info_for_litequery(
td::optional<ShardIdFull> shard,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) override {
promise.set_result(td::Status::Error("not implemented"));
}
void validated_new_block(BlockIdExt block_id) override {
}
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override {

View file

@ -458,18 +458,33 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) override {
get_block_handle(block_id, false, promise.wrap([](BlockHandle &&handle) -> ConstBlockHandle { return handle; }));
}
void get_block_by_lt_from_db_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
void get_block_data_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) override {
get_block_data_from_db_short(block_id, std::move(promise));
}
void get_block_state_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override {
get_shard_state_from_db_short(block_id, std::move(promise));
}
void get_block_by_lt_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
td::Promise<ConstBlockHandle> promise) override {
get_block_by_lt_from_db(account, lt, std::move(promise));
}
void get_block_by_unix_time_from_db_for_litequery(AccountIdPrefixFull account, UnixTime ts,
void get_block_by_unix_time_for_litequery(AccountIdPrefixFull account, UnixTime ts,
td::Promise<ConstBlockHandle> promise) override {
get_block_by_unix_time_from_db(account, ts, std::move(promise));
}
void get_block_by_seqno_from_db_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
void get_block_by_seqno_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) override {
get_block_by_seqno_from_db(account, seqno, std::move(promise));
}
void get_block_candidate_for_litequery(PublicKey source, BlockIdExt block_id, FileHash collated_data_hash,
td::Promise<BlockCandidate> promise) override {
promise.set_result(td::Status::Error("not implemented"));
}
void get_validator_groups_info_for_litequery(
td::optional<ShardIdFull> shard,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) override {
promise.set_result(td::Status::Error("not implemented"));
}
void validated_new_block(BlockIdExt block_id) override {
}
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override {

View file

@ -227,13 +227,13 @@ void ValidatorManagerImpl::sync_complete(td::Promise<td::Unit> promise) {
VLOG(VALIDATOR_WARNING) << "completed sync. Validating " << validator_groups_.size() << " groups";
for (auto &v : validator_groups_) {
if (!v.second.empty()) {
td::actor::send_closure(v.second, &ValidatorGroup::create_session);
if (!v.second.actor.empty()) {
td::actor::send_closure(v.second.actor, &ValidatorGroup::create_session);
}
}
for (auto &v : next_validator_groups_) {
if (!v.second.empty()) {
td::actor::send_closure(v.second, &ValidatorGroup::create_session);
if (!v.second.actor.empty()) {
td::actor::send_closure(v.second.actor, &ValidatorGroup::create_session);
}
}
}
@ -1282,6 +1282,10 @@ void ValidatorManagerImpl::set_next_block(BlockIdExt block_id, BlockIdExt next,
}
void ValidatorManagerImpl::set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) {
if (!candidates_buffer_.empty()) {
td::actor::send_closure(candidates_buffer_, &CandidatesBuffer::add_new_candidate, id,
PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}, candidate.collated_file_hash);
}
td::actor::send_closure(db_, &Db::store_block_candidate, std::move(candidate), std::move(promise));
}
@ -1696,9 +1700,12 @@ void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::read_gc_list, R.move_as_ok());
}
});
td::actor::send_closure(db_, &Db::get_destroyed_validator_sessions, std::move(P));
if (opts_->nonfinal_ls_queries_enabled()) {
candidates_buffer_ = td::actor::create_actor<CandidatesBuffer>("candidates-buffer", actor_id(this));
}
auto Q = td::PromiseCreator::lambda(
[SelfId = actor_id(this)](td::Result<std::vector<td::Ref<PersistentStateDescription>>> R) {
if (R.is_error()) {
@ -2025,8 +2032,8 @@ void ValidatorManagerImpl::update_shards() {
VLOG(VALIDATOR_DEBUG) << "total shards=" << new_shards.size() << " config shards=" << exp_vec.size();
std::map<ValidatorSessionId, td::actor::ActorOwn<ValidatorGroup>> new_validator_groups_;
std::map<ValidatorSessionId, td::actor::ActorOwn<ValidatorGroup>> new_next_validator_groups_;
std::map<ValidatorSessionId, ValidatorGroupEntry> new_validator_groups_;
std::map<ValidatorSessionId, ValidatorGroupEntry> new_next_validator_groups_;
bool force_recover = false;
{
@ -2058,8 +2065,8 @@ void ValidatorManagerImpl::update_shards() {
} else {
auto it2 = next_validator_groups_.find(legacy_val_group_id);
if (it2 != next_validator_groups_.end()) {
if (!it2->second.empty()) {
td::actor::send_closure(it2->second, &ValidatorGroup::start, prev, last_masterchain_block_id_);
if (!it2->second.actor.empty()) {
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
new_validator_groups_.emplace(val_group_id, std::move(it2->second));
} else {
@ -2067,7 +2074,7 @@ void ValidatorManagerImpl::update_shards() {
if (!G.empty()) {
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
new_validator_groups_.emplace(val_group_id, std::move(G));
new_validator_groups_.emplace(val_group_id, ValidatorGroupEntry{std::move(G), shard});
}
}
}
@ -2113,8 +2120,8 @@ void ValidatorManagerImpl::update_shards() {
} else {
auto it2 = next_validator_groups_.find(val_group_id);
if (it2 != next_validator_groups_.end()) {
if (!it2->second.empty()) {
td::actor::send_closure(it2->second, &ValidatorGroup::start, prev, last_masterchain_block_id_);
if (!it2->second.actor.empty()) {
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
new_validator_groups_.emplace(val_group_id, std::move(it2->second));
} else {
@ -2122,7 +2129,7 @@ void ValidatorManagerImpl::update_shards() {
if (!G.empty()) {
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
new_validator_groups_.emplace(val_group_id, std::move(G));
new_validator_groups_.emplace(val_group_id, ValidatorGroupEntry{std::move(G), shard});
}
}
}
@ -2142,23 +2149,24 @@ void ValidatorManagerImpl::update_shards() {
//CHECK(!it->second.empty());
new_next_validator_groups_.emplace(val_group_id, std::move(it->second));
} else {
new_next_validator_groups_.emplace(val_group_id,
create_validator_group(val_group_id, shard, val_set, opts, started_));
new_next_validator_groups_.emplace(
val_group_id,
ValidatorGroupEntry{create_validator_group(val_group_id, shard, val_set, opts, started_), shard});
}
}
}
std::vector<td::actor::ActorId<ValidatorGroup>> gc;
for (auto &v : validator_groups_) {
if (!v.second.empty()) {
if (!v.second.actor.empty()) {
gc_list_.push_back(v.first);
gc.push_back(v.second.release());
gc.push_back(v.second.actor.release());
}
}
for (auto &v : next_validator_groups_) {
if (!v.second.empty()) {
if (!v.second.actor.empty()) {
gc_list_.push_back(v.first);
gc.push_back(v.second.release());
gc.push_back(v.second.actor.release());
}
}
@ -2903,19 +2911,72 @@ void ValidatorManagerImpl::log_validator_session_stats(BlockIdExt block_id,
}
void ValidatorManagerImpl::get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) {
get_block_handle(
block_id, false,
[SelfId = actor_id(this), block_id, promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_ok() && R.ok()->is_applied()) {
promise.set_value(R.move_as_ok());
} else {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::process_block_handle_for_litequery_error, block_id,
std::move(R), std::move(promise));
}
});
get_block_handle(block_id, false,
[SelfId = actor_id(this), block_id, promise = std::move(promise),
allow_not_applied = opts_->nonfinal_ls_queries_enabled()](td::Result<BlockHandle> R) mutable {
if (R.is_ok() && (allow_not_applied || R.ok()->is_applied())) {
promise.set_value(R.move_as_ok());
} else {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::process_block_handle_for_litequery_error,
block_id, std::move(R), std::move(promise));
}
});
}
void ValidatorManagerImpl::get_block_by_lt_from_db_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
void ValidatorManagerImpl::get_block_data_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) {
if (candidates_buffer_.empty()) {
get_block_handle_for_litequery(
block_id, [manager = actor_id(this), promise = std::move(promise)](td::Result<ConstBlockHandle> R) mutable {
TRY_RESULT_PROMISE(promise, handle, std::move(R));
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db, std::move(handle),
std::move(promise));
});
} else {
td::actor::send_closure(
candidates_buffer_, &CandidatesBuffer::get_block_data, block_id,
[manager = actor_id(this), promise = std::move(promise), block_id](td::Result<td::Ref<BlockData>> R) mutable {
if (R.is_ok()) {
promise.set_result(R.move_as_ok());
return;
}
td::actor::send_closure(manager, &ValidatorManagerImpl::get_block_handle_for_litequery, block_id,
[manager, promise = std::move(promise)](td::Result<ConstBlockHandle> R) mutable {
TRY_RESULT_PROMISE(promise, handle, std::move(R));
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db,
std::move(handle), std::move(promise));
});
});
}
}
void ValidatorManagerImpl::get_block_state_for_litequery(BlockIdExt block_id,
td::Promise<td::Ref<ShardState>> promise) {
if (candidates_buffer_.empty()) {
get_block_handle_for_litequery(
block_id, [manager = actor_id(this), promise = std::move(promise)](td::Result<ConstBlockHandle> R) mutable {
TRY_RESULT_PROMISE(promise, handle, std::move(R));
td::actor::send_closure_later(manager, &ValidatorManager::get_shard_state_from_db, std::move(handle),
std::move(promise));
});
} else {
td::actor::send_closure(
candidates_buffer_, &CandidatesBuffer::get_block_state, block_id,
[manager = actor_id(this), promise = std::move(promise), block_id](td::Result<td::Ref<ShardState>> R) mutable {
if (R.is_ok()) {
promise.set_result(R.move_as_ok());
return;
}
td::actor::send_closure(manager, &ValidatorManagerImpl::get_block_handle_for_litequery,
block_id, [manager, promise = std::move(promise)](td::Result<ConstBlockHandle> R) mutable {
TRY_RESULT_PROMISE(promise, handle, std::move(R));
td::actor::send_closure_later(manager, &ValidatorManager::get_shard_state_from_db, std::move(handle),
std::move(promise));
});
});
}
}
void ValidatorManagerImpl::get_block_by_lt_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
td::Promise<ConstBlockHandle> promise) {
get_block_by_lt_from_db(
account, lt, [=, SelfId = actor_id(this), promise = std::move(promise)](td::Result<ConstBlockHandle> R) mutable {
@ -2928,7 +2989,7 @@ void ValidatorManagerImpl::get_block_by_lt_from_db_for_litequery(AccountIdPrefix
});
}
void ValidatorManagerImpl::get_block_by_unix_time_from_db_for_litequery(AccountIdPrefixFull account, UnixTime ts,
void ValidatorManagerImpl::get_block_by_unix_time_for_litequery(AccountIdPrefixFull account, UnixTime ts,
td::Promise<ConstBlockHandle> promise) {
get_block_by_unix_time_from_db(
account, ts, [=, SelfId = actor_id(this), promise = std::move(promise)](td::Result<ConstBlockHandle> R) mutable {
@ -2941,7 +3002,7 @@ void ValidatorManagerImpl::get_block_by_unix_time_from_db_for_litequery(AccountI
});
}
void ValidatorManagerImpl::get_block_by_seqno_from_db_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
void ValidatorManagerImpl::get_block_by_seqno_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) {
get_block_by_seqno_from_db(
account, seqno,
@ -3039,11 +3100,82 @@ void ValidatorManagerImpl::process_lookup_block_for_litequery_error(AccountIdPre
promise.set_error(std::move(err));
}
void ValidatorManagerImpl::get_block_candidate_for_litequery(PublicKey source, BlockIdExt block_id,
FileHash collated_data_hash,
td::Promise<BlockCandidate> promise) {
if (!opts_->nonfinal_ls_queries_enabled()) {
promise.set_error(td::Status::Error("query is not allowed"));
return;
}
get_block_candidate_from_db(source, block_id, collated_data_hash, std::move(promise));
}
void ValidatorManagerImpl::get_validator_groups_info_for_litequery(
td::optional<ShardIdFull> shard,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) {
if (!opts_->nonfinal_ls_queries_enabled()) {
promise.set_error(td::Status::Error("query is not allowed"));
return;
}
class Actor : public td::actor::Actor {
public:
explicit Actor(std::vector<td::actor::ActorId<ValidatorGroup>> groups,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise)
: groups_(std::move(groups)), promise_(std::move(promise)) {
}
void start_up() override {
pending_ = groups_.size();
if (pending_ == 0) {
promise_.set_result(std::move(result_));
stop();
return;
}
for (auto &x : groups_) {
td::actor::send_closure(
x, &ValidatorGroup::get_validator_group_info_for_litequery,
[SelfId = actor_id(this)](td::Result<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroupInfo>> R) {
td::actor::send_closure(SelfId, &Actor::on_result, R.is_ok() ? R.move_as_ok() : nullptr);
});
}
}
void on_result(tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroupInfo> r) {
if (r) {
result_->groups_.push_back(std::move(r));
}
--pending_;
if (pending_ == 0) {
promise_.set_result(std::move(result_));
stop();
}
}
private:
std::vector<td::actor::ActorId<ValidatorGroup>> groups_;
size_t pending_;
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise_;
tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups> result_ =
create_tl_object<lite_api::liteServer_nonfinal_validatorGroups>();
};
std::vector<td::actor::ActorId<ValidatorGroup>> groups;
for (auto &x : validator_groups_) {
if (x.second.actor.empty()) {
continue;
}
if (shard && shard.value() != x.second.shard) {
continue;
}
groups.push_back(x.second.actor.get());
}
td::actor::create_actor<Actor>("get-validator-groups-info", std::move(groups), std::move(promise)).release();
}
void ValidatorManagerImpl::get_validator_sessions_info(
td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionsInfo>> promise) {
std::vector<td::actor::ActorId<ValidatorGroup>> groups;
for (const auto& g : validator_groups_) {
groups.push_back(g.second.get());
groups.push_back(g.second.actor.get());
}
struct IntermediateData {
std::vector<td::actor::ActorId<ValidatorGroup>> groups;

View file

@ -29,6 +29,7 @@
#include "rldp/rldp.h"
#include "token-manager.h"
#include "queue-size-counter.hpp"
#include "impl/candidates-buffer.hpp"
#include "collator-node.hpp"
#include <map>
@ -252,8 +253,12 @@ class ValidatorManagerImpl : public ValidatorManager {
td::Ref<ValidatorSet> validator_set,
validatorsession::ValidatorSessionOptions opts,
bool create_catchain);
std::map<ValidatorSessionId, td::actor::ActorOwn<ValidatorGroup>> validator_groups_;
std::map<ValidatorSessionId, td::actor::ActorOwn<ValidatorGroup>> next_validator_groups_;
struct ValidatorGroupEntry {
td::actor::ActorOwn<ValidatorGroup> actor;
ShardIdFull shard;
};
std::map<ValidatorSessionId, ValidatorGroupEntry> validator_groups_;
std::map<ValidatorSessionId, ValidatorGroupEntry> next_validator_groups_;
std::set<ValidatorSessionId> check_gc_list_;
std::vector<ValidatorSessionId> gc_list_;
@ -607,17 +612,24 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) override;
void get_block_by_lt_from_db_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
void get_block_data_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) override;
void get_block_state_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override;
void get_block_by_lt_for_litequery(AccountIdPrefixFull account, LogicalTime lt,
td::Promise<ConstBlockHandle> promise) override;
void get_block_by_unix_time_from_db_for_litequery(AccountIdPrefixFull account, UnixTime ts,
void get_block_by_unix_time_for_litequery(AccountIdPrefixFull account, UnixTime ts,
td::Promise<ConstBlockHandle> promise) override;
void get_block_by_seqno_from_db_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
void get_block_by_seqno_for_litequery(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) override;
void process_block_handle_for_litequery_error(BlockIdExt block_id, td::Result<BlockHandle> r_handle,
td::Promise<ConstBlockHandle> promise);
void process_lookup_block_for_litequery_error(AccountIdPrefixFull account, int type, td::uint64 value,
td::Result<ConstBlockHandle> r_handle,
td::Promise<ConstBlockHandle> promise);
void get_block_candidate_for_litequery(PublicKey source, BlockIdExt block_id, FileHash collated_data_hash,
td::Promise<BlockCandidate> promise) override;
void get_validator_groups_info_for_litequery(
td::optional<ShardIdFull> shard,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) override;
void add_lite_query_stats(int lite_query_id) override {
++ls_stats_[lite_query_id];
@ -702,6 +714,8 @@ class ValidatorManagerImpl : public ValidatorManager {
std::map<int, td::uint32> ls_stats_; // lite_api ID -> count, 0 for unknown
td::uint32 ls_stats_check_ext_messages_{0};
td::actor::ActorOwn<CandidatesBuffer> candidates_buffer_;
struct Collator {
td::actor::ActorOwn<CollatorNode> actor;
std::set<ShardIdFull> shards;

View file

@ -23,6 +23,7 @@
#include "td/utils/overloaded.h"
#include "ton/ton-io.hpp"
#include "validator/full-node.h"
#include "full-node-serializer.hpp"
namespace ton {
@ -219,52 +220,54 @@ void DownloadBlockNew::got_data(td::BufferSlice data) {
}
auto f = F.move_as_ok();
if (f->get_id() == ton_api::tonNode_dataFullEmpty::ID) {
abort_query(td::Status::Error(ErrorCode::notready, "node doesn't have this block"));
return;
}
BlockIdExt id;
td::BufferSlice proof, block_data;
bool is_link;
td::Status S = deserialize_block_full(*f, id, proof, block_data, is_link, overlay::Overlays::max_fec_broadcast_size());
if (S.is_error()) {
abort_query(S.move_as_error_prefix("cannot deserialize block: "));
return;
}
ton_api::downcast_call(
*f.get(),
td::overloaded(
[&](ton_api::tonNode_dataFullEmpty &x) {
abort_query(td::Status::Error(ErrorCode::notready, "node doesn't have this block"));
},
[&, self = this](ton_api::tonNode_dataFull &x) {
if (!allow_partial_proof_ && x.is_link_) {
abort_query(td::Status::Error(ErrorCode::notready, "node doesn't have proof for this block"));
return;
}
auto id = create_block_id(x.id_);
if (block_id_.is_valid() && id != block_id_) {
abort_query(td::Status::Error(ErrorCode::notready, "received data for wrong block"));
return;
}
block_.id = id;
block_.data = std::move(x.block_);
if (td::sha256_bits256(block_.data.as_slice()) != id.file_hash) {
abort_query(td::Status::Error(ErrorCode::notready, "received data with bad hash"));
return;
}
if (!allow_partial_proof_ && is_link) {
abort_query(td::Status::Error(ErrorCode::notready, "node doesn't have proof for this block"));
return;
}
if (block_id_.is_valid() && id != block_id_) {
abort_query(td::Status::Error(ErrorCode::notready, "received data for wrong block"));
return;
}
block_.id = id;
block_.data = std::move(block_data);
if (td::sha256_bits256(block_.data.as_slice()) != id.file_hash) {
abort_query(td::Status::Error(ErrorCode::notready, "received data with bad hash"));
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(self)](td::Result<td::Unit> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query,
R.move_as_error_prefix("received bad proof: "));
} else {
td::actor::send_closure(SelfId, &DownloadBlockNew::checked_block_proof);
}
});
if (block_id_.is_valid()) {
if (x.is_link_) {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_proof_link,
block_id_, std::move(x.proof_), std::move(P));
} else {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_proof, block_id_,
std::move(x.proof_), std::move(P));
}
} else {
CHECK(!x.is_link_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_is_next_proof,
prev_id_, id, std::move(x.proof_), std::move(P));
}
}));
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query, R.move_as_error_prefix("received bad proof: "));
} else {
td::actor::send_closure(SelfId, &DownloadBlockNew::checked_block_proof);
}
});
if (block_id_.is_valid()) {
if (is_link) {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_proof_link, block_id_,
std::move(proof), std::move(P));
} else {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_proof, block_id_,
std::move(proof), std::move(P));
}
} else {
CHECK(!is_link);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::validate_block_is_next_proof, prev_id_, id,
std::move(proof), std::move(P));
}
}
void DownloadBlockNew::got_data_from_db(td::BufferSlice data) {

View file

@ -21,6 +21,7 @@
#include "ton/ton-io.hpp"
#include "td/utils/overloaded.h"
#include "common/delay.h"
#include "ton/lite-tl.hpp"
#include "ton/ton-tl.hpp"
#include "td/utils/Random.h"
@ -70,7 +71,9 @@ void ValidatorGroup::generated_block_candidate(std::shared_ptr<CachedCollatedBlo
cached_collated_block_ = nullptr;
}
} else {
cache->result = R.move_as_ok();
auto candidate = R.move_as_ok();
add_available_block_candidate(candidate.pubkey.as_bits256(), candidate.id, candidate.collated_file_hash);
cache->result = std::move(candidate);
for (auto &p : cache->promises) {
p.set_value(cache->result.value().clone());
}
@ -117,6 +120,8 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
[&](UnixTime ts) {
td::actor::send_closure(SelfId, &ValidatorGroup::update_approve_cache, block_to_cache_key(block),
ts);
td::actor::send_closure(SelfId, &ValidatorGroup::add_available_block_candidate, block.pubkey.as_bits256(),
block.id, block.collated_file_hash);
promise.set_result(ts);
},
[&](CandidateReject reject) {
@ -213,6 +218,10 @@ void ValidatorGroup::get_approved_candidate(PublicKey source, RootHash root_hash
std::move(promise));
}
BlockIdExt ValidatorGroup::create_next_block_id(RootHash root_hash, FileHash file_hash) const {
return BlockIdExt{create_next_block_id_simple(), root_hash, file_hash};
}
BlockId ValidatorGroup::create_next_block_id_simple() const {
BlockSeqno seqno = 0;
for (auto &p : prev_block_ids_) {
@ -223,10 +232,6 @@ BlockId ValidatorGroup::create_next_block_id_simple() const {
return BlockId{shard_.workchain, shard_.shard, seqno + 1};
}
BlockIdExt ValidatorGroup::create_next_block_id(RootHash root_hash, FileHash file_hash) const {
return BlockIdExt{create_next_block_id_simple(), root_hash, file_hash};
}
std::unique_ptr<validatorsession::ValidatorSession::Callback> ValidatorGroup::make_validator_session_callback() {
class Callback : public validatorsession::ValidatorSession::Callback {
public:
@ -382,6 +387,47 @@ void ValidatorGroup::destroy() {
stop();
}
void ValidatorGroup::get_validator_group_info_for_litequery(
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroupInfo>> promise) {
if (session_.empty()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not started"));
return;
}
td::actor::send_closure(
session_, &validatorsession::ValidatorSession::get_validator_group_info_for_litequery, last_known_round_id_,
[SelfId = actor_id(this), promise = std::move(promise), round = last_known_round_id_](
td::Result<std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>>> R) mutable {
TRY_RESULT_PROMISE(promise, result, std::move(R));
td::actor::send_closure(SelfId, &ValidatorGroup::get_validator_group_info_for_litequery_cont, round,
std::move(result), std::move(promise));
});
}
void ValidatorGroup::get_validator_group_info_for_litequery_cont(
td::uint32 expected_round, std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>> candidates,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroupInfo>> promise) {
if (expected_round != last_known_round_id_) {
candidates.clear();
}
BlockId next_block_id = create_next_block_id_simple();
for (auto &candidate : candidates) {
BlockIdExt id{next_block_id, candidate->id_->block_id_->root_hash_, candidate->id_->block_id_->file_hash_};
candidate->id_->block_id_ = create_tl_lite_block_id(id);
candidate->available_ =
available_block_candidates_.count({candidate->id_->creator_, id, candidate->id_->collated_data_hash_});
}
auto result = create_tl_object<lite_api::liteServer_nonfinal_validatorGroupInfo>();
result->next_block_id_ = create_tl_lite_block_id_simple(next_block_id);
for (const BlockIdExt& prev : prev_block_ids_) {
result->prev_.push_back(create_tl_lite_block_id(prev));
}
result->cc_seqno_ = validator_set_->get_catchain_seqno();
result->candidates_ = std::move(candidates);
promise.set_result(std::move(result));
}
void ValidatorGroup::get_session_info(
td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise) {
if (session_.empty() || !started_) {

View file

@ -46,8 +46,8 @@ class ValidatorGroup : public td::actor::Actor {
bool send_broadcast, td::Promise<td::Unit> promise, bool is_retry = false);
void get_approved_candidate(PublicKey source, RootHash root_hash, FileHash file_hash,
FileHash collated_data_file_hash, td::Promise<BlockCandidate> promise);
BlockId create_next_block_id_simple() const;
BlockIdExt create_next_block_id(RootHash root_hash, FileHash file_hash) const;
BlockId create_next_block_id_simple() const;
void start(std::vector<BlockIdExt> prev, BlockIdExt min_masterchain_block_id);
void create_session();
@ -59,6 +59,9 @@ class ValidatorGroup : public td::actor::Actor {
}
}
void get_validator_group_info_for_litequery(
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroupInfo>> promise);
void get_session_info(td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise);
ValidatorGroup(ShardIdFull shard, PublicKeyHash local_id, ValidatorSessionId session_id,
@ -147,6 +150,17 @@ class ValidatorGroup : public td::actor::Actor {
static CacheKey block_to_cache_key(const BlockCandidate& block) {
return std::make_tuple(block.pubkey.as_bits256(), block.id, sha256_bits256(block.data), block.collated_file_hash);
}
void get_validator_group_info_for_litequery_cont(
td::uint32 expected_round,
std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>> candidates,
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroupInfo>> promise);
std::set<std::tuple<td::Bits256, BlockIdExt, FileHash>> available_block_candidates_; // source, id, collated hash
void add_available_block_candidate(td::Bits256 source, BlockIdExt id, FileHash collated_data_hash) {
available_block_candidates_.emplace(source, id, collated_data_hash);
}
};
} // namespace validator

View file

@ -124,6 +124,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
bool get_disable_rocksdb_stats() const override {
return disable_rocksdb_stats_;
}
bool nonfinal_ls_queries_enabled() const override {
return nonfinal_ls_queries_enabled_;
}
ValidatorMode validator_mode() const override {
return validator_mode_;
}
@ -192,6 +195,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
void set_disable_rocksdb_stats(bool value) override {
disable_rocksdb_stats_ = value;
}
void set_nonfinal_ls_queries_enabled(bool value) override {
nonfinal_ls_queries_enabled_ = value;
}
void set_validator_mode(ValidatorMode value) override {
validator_mode_ = value;
}
@ -239,6 +245,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
size_t max_open_archive_files_ = 0;
double archive_preload_period_ = 0.0;
bool disable_rocksdb_stats_;
bool nonfinal_ls_queries_enabled_ = false;
ValidatorMode validator_mode_ = validator_normal;
};

View file

@ -85,6 +85,7 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual size_t get_max_open_archive_files() const = 0;
virtual double get_archive_preload_period() const = 0;
virtual bool get_disable_rocksdb_stats() const = 0;
virtual bool nonfinal_ls_queries_enabled() const = 0;
virtual ValidatorMode validator_mode() const = 0;
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
@ -108,6 +109,7 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual void set_max_open_archive_files(size_t value) = 0;
virtual void set_archive_preload_period(double value) = 0;
virtual void set_disable_rocksdb_stats(bool value) = 0;
virtual void set_nonfinal_ls_queries_enabled(bool value) = 0;
virtual void set_validator_mode(ValidatorMode value) = 0;
static td::Ref<ValidatorManagerOptions> create(