mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
TON Validation Contest: Reference solution and grader
This commit is contained in:
parent
1ee3e5d6a7
commit
d8e29f8b67
13 changed files with 6066 additions and 6 deletions
|
@ -447,6 +447,9 @@ add_subdirectory(dht-server)
|
|||
add_subdirectory(utils)
|
||||
add_subdirectory(http)
|
||||
add_subdirectory(rldp-http-proxy)
|
||||
|
||||
add_subdirectory(contest/solution)
|
||||
add_subdirectory(contest/grader)
|
||||
endif()
|
||||
#END internal
|
||||
|
||||
|
|
5
contest/grader/CMakeLists.txt
Normal file
5
contest/grader/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
add_executable(contest-grader grader.cpp)
|
||||
target_include_directories(contest-grader PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>)
|
||||
target_link_libraries(contest-grader contest-solution tdutils tdactor ton_block ton_crypto tl-utils tl_api git terminal)
|
265
contest/grader/grader.cpp
Normal file
265
contest/grader/grader.cpp
Normal file
|
@ -0,0 +1,265 @@
|
|||
#include "td/utils/OptionParser.h"
|
||||
#include <fstream>
|
||||
#include "overlay/overlays.h"
|
||||
|
||||
#include "adnl/adnl-ext-client.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
#include "mc-config.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "block-auto.h"
|
||||
#include "contest/solution/solution.hpp"
|
||||
#include "td/utils/PathView.h"
|
||||
#include "td/utils/port/signals.h"
|
||||
#include "vm/vm.h"
|
||||
#include "vm/cells/MerkleUpdate.h"
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
using namespace ton;
|
||||
|
||||
static constexpr td::uint64 CPU_USAGE_PER_SEC = 1000000;
|
||||
|
||||
static td::uint64 get_cpu_usage() {
|
||||
rusage usage;
|
||||
CHECK(getrusage(RUSAGE_SELF, &usage) == 0);
|
||||
return (td::uint64)usage.ru_utime.tv_sec * 1000000 + (td::uint64)usage.ru_utime.tv_usec;
|
||||
}
|
||||
|
||||
class ContestGrader : public td::actor::Actor {
|
||||
public:
|
||||
explicit ContestGrader(std::string tests_dir) : tests_dir_(tests_dir) {
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
vm::init_vm().ensure();
|
||||
scan_tests_dir();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
void scan_tests_dir() {
|
||||
auto walk_status = td::WalkPath::run(tests_dir_, [&](td::CSlice name, td::WalkPath::Type type) {
|
||||
if (type == td::WalkPath::Type::NotDir && td::ends_with(name, ".bin")) {
|
||||
test_files_.push_back(td::PathView::relative(name.str(), tests_dir_).str());
|
||||
}
|
||||
return td::WalkPath::Action::Continue;
|
||||
});
|
||||
walk_status.ensure();
|
||||
LOG_CHECK(!test_files_.empty()) << "No tests found";
|
||||
std::sort(test_files_.begin(), test_files_.end());
|
||||
|
||||
test_name_column_width_ = 4;
|
||||
for (const std::string& s : test_files_) {
|
||||
test_name_column_width_ = std::max(test_name_column_width_, s.size());
|
||||
}
|
||||
test_idx_column_width_ = 1;
|
||||
size_t threshold = 10;
|
||||
while (test_files_.size() >= threshold) {
|
||||
++test_idx_column_width_;
|
||||
threshold *= 10;
|
||||
}
|
||||
separator_length_ = test_idx_column_width_ + test_name_column_width_ + 60;
|
||||
|
||||
printf("Executing %lu tests\n", test_files_.size());
|
||||
printf("%s\n", std::string(separator_length_, '=').c_str());
|
||||
printf("%*s %-*s Time CPU Status Comment\n", (int)test_idx_column_width_, "#",
|
||||
(int)test_name_column_width_, "Name");
|
||||
printf("%s\n", std::string(separator_length_, '=').c_str());
|
||||
}
|
||||
|
||||
void run_next_test() {
|
||||
if (test_idx_ == test_files_.size()) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
auto r_test = read_test_file();
|
||||
if (r_test.is_error()) {
|
||||
printf("%*lu %-*s %8.5f %8.5f FATAL %s\n", (int)test_idx_column_width_, test_idx_ + 1,
|
||||
(int)test_name_column_width_, test_files_[test_idx_].c_str(), 0.0, 0.0,
|
||||
r_test.error().to_string().c_str());
|
||||
fflush(stdout);
|
||||
++cnt_fatal_;
|
||||
++test_idx_;
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
|
||||
auto test = r_test.move_as_ok();
|
||||
BlockIdExt block_id = create_block_id(test->block_id_);
|
||||
td::BufferSlice block_data = std::move(test->block_data_);
|
||||
td::BufferSlice collated_data = std::move(test->collated_data_);
|
||||
bool valid = test->valid_;
|
||||
|
||||
td::Ref<vm::Cell> original_merkle_update;
|
||||
auto S = [&]() -> td::Status {
|
||||
TRY_RESULT(root, vm::std_boc_deserialize(block_data));
|
||||
block::gen::Block::Record rec;
|
||||
if (!block::gen::t_Block.cell_unpack(root, rec)) {
|
||||
return td::Status::Error("Failed to parse block root");
|
||||
}
|
||||
vm::CellSlice cs{rec.state_update->load_cell().move_as_ok()};
|
||||
if (cs.special_type() != vm::CellTraits::SpecialType::MerkleUpdate) {
|
||||
return td::Status::Error("Invalid Merkle Update in block");
|
||||
}
|
||||
original_merkle_update = rec.state_update;
|
||||
rec.state_update = vm::CellBuilder{}.finalize_novm();
|
||||
if (!block::gen::pack_cell(root, rec)) {
|
||||
return td::Status::Error("Failed to pack new block root");
|
||||
}
|
||||
TRY_RESULT_ASSIGN(block_data, vm::std_boc_serialize(root, 31));
|
||||
return td::Status::OK();
|
||||
}();
|
||||
if (S.is_error()) {
|
||||
printf("%*lu %-*s %8.5f %8.5f FATAL %s\n", (int)test_idx_column_width_, test_idx_ + 1,
|
||||
(int)test_name_column_width_, test_files_[test_idx_].c_str(), 0.0, 0.0, S.to_string().c_str());
|
||||
fflush(stdout);
|
||||
++cnt_fatal_;
|
||||
++test_idx_;
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
|
||||
run_contest_solution(
|
||||
block_id, std::move(block_data), std::move(collated_data),
|
||||
[=, SelfId = actor_id(this), timer = td::Timer{}, start_cpu = get_cpu_usage()](td::Result<td::BufferSlice> R) {
|
||||
td::actor::send_closure(SelfId, &ContestGrader::got_solution_result, std::move(R), valid,
|
||||
original_merkle_update, timer.elapsed(),
|
||||
(double)(get_cpu_usage() - start_cpu) / CPU_USAGE_PER_SEC);
|
||||
});
|
||||
}
|
||||
|
||||
td::Result<tl_object_ptr<ton_api::contest_test>> read_test_file() {
|
||||
TRY_RESULT(data, td::read_file(tests_dir_ + "/" + test_files_[test_idx_]));
|
||||
return ton::fetch_tl_object<ton_api::contest_test>(data, true);
|
||||
}
|
||||
|
||||
void got_solution_result(td::Result<td::BufferSlice> res, bool valid, td::Ref<vm::Cell> original_merkle_update,
|
||||
double elapsed, double cpu_time) {
|
||||
bool got_valid = res.is_ok();
|
||||
if (got_valid != valid) {
|
||||
printf("%*lu %-*s %8.5f %8.5f ERROR expected %s, found %s\n", (int)test_idx_column_width_, test_idx_ + 1,
|
||||
(int)test_name_column_width_, test_files_[test_idx_].c_str(), elapsed, cpu_time,
|
||||
(valid ? "VALID" : "INVALID"), (got_valid ? "VALID" : "INVALID"));
|
||||
fflush(stdout);
|
||||
++cnt_fail_;
|
||||
++test_idx_;
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
if (!valid) {
|
||||
printf("%*lu %-*s %8.5f %8.5f OK block is INVALID\n", (int)test_idx_column_width_, test_idx_ + 1,
|
||||
(int)test_name_column_width_, test_files_[test_idx_].c_str(), elapsed, cpu_time);
|
||||
fflush(stdout);
|
||||
++cnt_ok_;
|
||||
++test_idx_;
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
auto S = check_merkle_update(res.move_as_ok(), original_merkle_update);
|
||||
if (S.is_error()) {
|
||||
printf("%*lu %-*s %8.5f %8.5f ERROR invalid Merkle update %s\n", (int)test_idx_column_width_, test_idx_ + 1,
|
||||
(int)test_name_column_width_, test_files_[test_idx_].c_str(), elapsed, cpu_time, S.to_string().c_str());
|
||||
fflush(stdout);
|
||||
++cnt_fail_;
|
||||
++test_idx_;
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%*lu %-*s %8.5f %8.5f OK block is VALID\n", (int)test_idx_column_width_, test_idx_ + 1,
|
||||
(int)test_name_column_width_, test_files_[test_idx_].c_str(), elapsed, cpu_time);
|
||||
fflush(stdout);
|
||||
total_time_ += elapsed;
|
||||
total_cpu_time_ += cpu_time;
|
||||
++cnt_ok_;
|
||||
++test_idx_;
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
td::Status check_merkle_update(td::Slice data, td::Ref<vm::Cell> original_merkle_update) {
|
||||
TRY_RESULT(new_merkle_update, vm::std_boc_deserialize(data));
|
||||
TRY_STATUS(vm::MerkleUpdate::validate(new_merkle_update));
|
||||
|
||||
vm::CellSlice new_cs{new_merkle_update->load_cell().move_as_ok()};
|
||||
vm::CellSlice old_cs{original_merkle_update->load_cell().move_as_ok()};
|
||||
if (new_cs.lex_cmp(old_cs)) { // compare hashes in Merkle update roots
|
||||
return td::Status::Error("Merkle Update does not match the original Merkle Update");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void finish() {
|
||||
printf("%s\n", std::string(separator_length_, '=').c_str());
|
||||
printf("Passed %lu/%lu tests\n", cnt_ok_, test_files_.size());
|
||||
printf("Total time (only passed valid tests): %.5f\n", total_time_);
|
||||
printf("Total CPU time (only passed valid tests): %.5f\n", total_cpu_time_);
|
||||
if (cnt_fail_ > 0) {
|
||||
printf("Failed %lu/%lu tests\n", cnt_fail_, test_files_.size());
|
||||
}
|
||||
if (cnt_fatal_ > 0) {
|
||||
printf("FATAL ERROR %lu/%lu tests\n", cnt_fatal_, test_files_.size());
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string tests_dir_;
|
||||
std::vector<std::string> test_files_;
|
||||
size_t test_idx_ = 0;
|
||||
size_t cnt_ok_ = 0, cnt_fail_ = 0, cnt_fatal_ = 0;
|
||||
|
||||
size_t test_idx_column_width_ = 0;
|
||||
size_t test_name_column_width_ = 0;
|
||||
size_t separator_length_ = 0;
|
||||
|
||||
double total_time_ = 0.0;
|
||||
double total_cpu_time_ = 0.0;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
SET_VERBOSITY_LEVEL(verbosity_ERROR);
|
||||
|
||||
td::actor::ActorOwn<ContestGrader> x;
|
||||
td::unique_ptr<td::LogInterface> logger_;
|
||||
SCOPE_EXIT {
|
||||
td::log_interface = td::default_log_interface;
|
||||
};
|
||||
|
||||
td::OptionParser p;
|
||||
p.set_description("Block validation contest");
|
||||
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
|
||||
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
|
||||
SET_VERBOSITY_LEVEL(v);
|
||||
});
|
||||
p.add_option('h', "help", "prints a help message", [&]() {
|
||||
char b[10240];
|
||||
td::StringBuilder sb(td::MutableSlice{b, 10000});
|
||||
sb << p;
|
||||
std::cout << sb.as_cslice().c_str();
|
||||
std::exit(2);
|
||||
});
|
||||
std::string tests_dir = "tests/";
|
||||
p.add_option('d', "tests", "directory with tests (default: tests/)",
|
||||
[&](td::Slice arg) { tests_dir = arg.str() + "/"; });
|
||||
td::uint32 threads = 8;
|
||||
p.add_checked_option('t', "threads", "number of threads (default: 8)", [&](td::Slice arg) {
|
||||
TRY_RESULT_ASSIGN(threads, td::to_integer_safe<td::uint32>(arg));
|
||||
return td::Status::OK();
|
||||
});
|
||||
|
||||
p.run(argc, argv).ensure();
|
||||
td::actor::Scheduler scheduler({threads});
|
||||
|
||||
scheduler.run_in_context([&] { x = td::actor::create_actor<ContestGrader>("grader", tests_dir); });
|
||||
while (scheduler.run(1)) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
6
contest/solution/CMakeLists.txt
Normal file
6
contest/solution/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
add_library(contest-solution STATIC solution.hpp solution.cpp contest-validate-query.cpp contest-validate-query.hpp)
|
||||
target_include_directories(contest-solution PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>)
|
||||
target_include_directories(contest-solution PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../validator>)
|
||||
target_link_libraries(contest-solution PRIVATE tdactor tdutils ton_block ton_validator validator ton_crypto)
|
5408
contest/solution/contest-validate-query.cpp
Normal file
5408
contest/solution/contest-validate-query.cpp
Normal file
File diff suppressed because it is too large
Load diff
341
contest/solution/contest-validate-query.hpp
Normal file
341
contest/solution/contest-validate-query.hpp
Normal file
|
@ -0,0 +1,341 @@
|
|||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "vm/cells.h"
|
||||
#include "vm/dict.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "block/transaction.h"
|
||||
#include "shard.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "common/global-version.h"
|
||||
#include "tonlib/tonlib/ExtClient.h"
|
||||
|
||||
namespace solution {
|
||||
|
||||
using namespace ton;
|
||||
using namespace ton::validator;
|
||||
|
||||
using td::Ref;
|
||||
|
||||
class ErrorCtxAdd;
|
||||
class ErrorCtxSet;
|
||||
|
||||
struct ErrorCtx {
|
||||
protected:
|
||||
friend class ErrorCtxAdd;
|
||||
friend class ErrorCtxSet;
|
||||
std::vector<std::string> entries_;
|
||||
|
||||
public:
|
||||
ErrorCtx() = default;
|
||||
ErrorCtx(std::vector<std::string> str_list) : entries_(std::move(str_list)) {
|
||||
}
|
||||
ErrorCtx(std::string str) : entries_{str} {
|
||||
}
|
||||
std::string as_string() const;
|
||||
ErrorCtxAdd add_guard(std::string str_add);
|
||||
ErrorCtxSet set_guard(std::string str);
|
||||
ErrorCtxSet set_guard(std::vector<std::string> str_list);
|
||||
};
|
||||
|
||||
class ErrorCtxAdd {
|
||||
ErrorCtx& ctx_;
|
||||
|
||||
public:
|
||||
ErrorCtxAdd(ErrorCtx& ctx, std::string ctx_elem) : ctx_(ctx) {
|
||||
ctx_.entries_.push_back(std::move(ctx_elem));
|
||||
}
|
||||
~ErrorCtxAdd() {
|
||||
ctx_.entries_.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
class ErrorCtxSet {
|
||||
ErrorCtx& ctx_;
|
||||
std::vector<std::string> old_ctx_;
|
||||
|
||||
public:
|
||||
ErrorCtxSet(ErrorCtx& ctx, std::vector<std::string> new_ctx) : ctx_(ctx) {
|
||||
old_ctx_ = std::move(ctx_.entries_);
|
||||
ctx_.entries_ = std::move(new_ctx);
|
||||
}
|
||||
ErrorCtxSet(ErrorCtx& ctx, std::string new_ctx) : ErrorCtxSet(ctx, std::vector<std::string>{new_ctx}) {
|
||||
}
|
||||
~ErrorCtxSet() {
|
||||
ctx_.entries_ = std::move(old_ctx_);
|
||||
}
|
||||
};
|
||||
|
||||
inline ErrorCtxAdd ErrorCtx::add_guard(std::string str) {
|
||||
return ErrorCtxAdd(*this, std::move(str));
|
||||
}
|
||||
|
||||
inline ErrorCtxSet ErrorCtx::set_guard(std::string str) {
|
||||
return ErrorCtxSet(*this, std::move(str));
|
||||
}
|
||||
|
||||
inline ErrorCtxSet ErrorCtx::set_guard(std::vector<std::string> str_list) {
|
||||
return ErrorCtxSet(*this, std::move(str_list));
|
||||
}
|
||||
|
||||
class ContestValidateQuery : public td::actor::Actor {
|
||||
static constexpr int supported_version() {
|
||||
return SUPPORTED_VERSION;
|
||||
}
|
||||
static constexpr long long supported_capabilities() {
|
||||
return ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion | ton::capShortDequeue |
|
||||
ton::capStoreOutMsgQueueSize | ton::capMsgMetadata | ton::capDeferMessages | ton::capFullCollatedData;
|
||||
}
|
||||
|
||||
public:
|
||||
ContestValidateQuery(BlockIdExt block_id, td::BufferSlice block_data, td::BufferSlice collated_data,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
|
||||
private:
|
||||
int verbosity{0};
|
||||
int pending{0};
|
||||
const ShardIdFull shard_;
|
||||
const BlockIdExt id_;
|
||||
std::vector<BlockIdExt> prev_blocks;
|
||||
std::vector<Ref<ShardState>> prev_states;
|
||||
td::BufferSlice block_data, collated_data;
|
||||
td::Promise<td::BufferSlice> main_promise;
|
||||
bool after_merge_{false};
|
||||
bool after_split_{false};
|
||||
bool before_split_{false};
|
||||
bool want_split_{false};
|
||||
bool want_merge_{false};
|
||||
bool is_key_block_{false};
|
||||
bool update_shard_cc_{false};
|
||||
bool prev_key_block_exists_{false};
|
||||
bool debug_checks_{false};
|
||||
bool outq_cleanup_partial_{false};
|
||||
BlockSeqno prev_key_seqno_{~0u};
|
||||
int stage_{0};
|
||||
td::BitArray<64> shard_pfx_;
|
||||
int shard_pfx_len_;
|
||||
td::Bits256 created_by_;
|
||||
|
||||
Ref<vm::Cell> prev_state_root_;
|
||||
std::shared_ptr<vm::CellUsageTree> state_usage_tree_; // used to construct Merkle update
|
||||
|
||||
ErrorCtx error_ctx_;
|
||||
|
||||
td::Ref<MasterchainStateQ> mc_state_;
|
||||
td::Ref<vm::Cell> mc_state_root_;
|
||||
BlockIdExt mc_blkid_;
|
||||
ton::BlockSeqno mc_seqno_{0};
|
||||
|
||||
Ref<vm::Cell> block_root_;
|
||||
std::vector<Ref<vm::Cell>> collated_roots_;
|
||||
std::map<RootHash, Ref<vm::Cell>> virt_roots_;
|
||||
std::unique_ptr<vm::Dictionary> top_shard_descr_dict_;
|
||||
block::gen::ExtraCollatedData::Record extra_collated_data_;
|
||||
bool have_extra_collated_data_ = false;
|
||||
|
||||
Ref<vm::Cell> recover_create_msg_, mint_msg_; // from McBlockExtra (UNCHECKED)
|
||||
|
||||
std::unique_ptr<block::ConfigInfo> config_;
|
||||
std::unique_ptr<block::ShardConfig> old_shard_conf_; // from reference mc state
|
||||
std::unique_ptr<block::ShardConfig> new_shard_conf_; // from shard_hashes_ in mc blocks
|
||||
Ref<block::WorkchainInfo> wc_info_;
|
||||
Ref<vm::Cell> old_mparams_;
|
||||
bool accept_msgs_{true};
|
||||
|
||||
ton::BlockSeqno min_shard_ref_mc_seqno_{~0U};
|
||||
ton::LogicalTime max_shard_lt_{0};
|
||||
|
||||
int global_id_{0};
|
||||
ton::BlockSeqno vert_seqno_{~0U};
|
||||
bool ihr_enabled_{false};
|
||||
bool create_stats_enabled_{false};
|
||||
ton::BlockSeqno prev_key_block_seqno_;
|
||||
ton::BlockIdExt prev_key_block_;
|
||||
ton::LogicalTime prev_key_block_lt_;
|
||||
std::unique_ptr<block::BlockLimits> block_limits_;
|
||||
std::unique_ptr<block::BlockLimitStatus> block_limit_status_;
|
||||
td::uint64 total_gas_used_{0}, total_special_gas_used_{0};
|
||||
|
||||
LogicalTime start_lt_, end_lt_;
|
||||
UnixTime now_{~0u};
|
||||
|
||||
ton::Bits256 rand_seed_;
|
||||
std::vector<block::StoragePrices> storage_prices_;
|
||||
block::StoragePhaseConfig storage_phase_cfg_{&storage_prices_};
|
||||
block::ComputePhaseConfig compute_phase_cfg_;
|
||||
block::ActionPhaseConfig action_phase_cfg_;
|
||||
td::RefInt256 masterchain_create_fee_, basechain_create_fee_;
|
||||
|
||||
std::vector<block::McShardDescr> neighbors_;
|
||||
std::map<BlockSeqno, Ref<MasterchainStateQ>> aux_mc_states_;
|
||||
|
||||
block::ShardState ps_;
|
||||
block::ShardState ns_;
|
||||
bool processed_upto_updated_{false};
|
||||
std::unique_ptr<vm::AugmentedDictionary> sibling_out_msg_queue_;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> sibling_processed_upto_;
|
||||
|
||||
std::map<td::Bits256, int> block_create_count_;
|
||||
unsigned block_create_total_{0};
|
||||
|
||||
std::unique_ptr<vm::AugmentedDictionary> in_msg_dict_, out_msg_dict_, account_blocks_dict_;
|
||||
block::ValueFlow value_flow_;
|
||||
block::CurrencyCollection import_created_, transaction_fees_, total_burned_{0}, fees_burned_{0};
|
||||
td::RefInt256 import_fees_;
|
||||
|
||||
ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL};
|
||||
ton::Bits256 proc_hash_ = ton::Bits256::zero(), claimed_proc_hash_, min_enq_hash_;
|
||||
|
||||
std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_proc_lt_;
|
||||
std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_emitted_lt_;
|
||||
|
||||
std::map<std::pair<StdSmcAddress, td::uint64>, Ref<vm::Cell>> removed_dispatch_queue_messages_;
|
||||
std::map<std::pair<StdSmcAddress, td::uint64>, Ref<vm::Cell>> new_dispatch_queue_messages_;
|
||||
std::set<StdSmcAddress> account_expected_defer_all_messages_;
|
||||
td::uint64 old_out_msg_queue_size_ = 0;
|
||||
bool out_msg_queue_size_known_ = false;
|
||||
bool have_out_msg_queue_size_in_state_ = false;
|
||||
|
||||
bool msg_metadata_enabled_ = false;
|
||||
bool deferring_messages_enabled_ = false;
|
||||
bool store_out_msg_queue_size_ = false;
|
||||
|
||||
td::uint64 processed_account_dispatch_queues_ = 0;
|
||||
bool have_unprocessed_account_dispatch_queue_ = false;
|
||||
|
||||
WorkchainId workchain() const {
|
||||
return shard_.workchain;
|
||||
}
|
||||
|
||||
void finish_query();
|
||||
void abort_query(td::Status error);
|
||||
bool reject_query(std::string error, td::BufferSlice reason = {});
|
||||
bool reject_query(std::string err_msg, td::Status error, td::BufferSlice reason = {});
|
||||
bool soft_reject_query(std::string error, td::BufferSlice reason = {});
|
||||
void start_up() override;
|
||||
|
||||
bool fatal_error(td::Status error);
|
||||
bool fatal_error(int err_code, std::string err_msg);
|
||||
bool fatal_error(int err_code, std::string err_msg, td::Status error);
|
||||
bool fatal_error(std::string err_msg, int err_code = -666);
|
||||
|
||||
std::string error_ctx() const {
|
||||
return error_ctx_.as_string();
|
||||
}
|
||||
ErrorCtxAdd error_ctx_add_guard(std::string str) {
|
||||
return error_ctx_.add_guard(std::move(str));
|
||||
}
|
||||
ErrorCtxSet error_ctx_set_guard(std::string str) {
|
||||
return error_ctx_.set_guard(std::move(str));
|
||||
}
|
||||
|
||||
td::actor::ActorId<ContestValidateQuery> get_self() {
|
||||
return actor_id(this);
|
||||
}
|
||||
|
||||
td::Result<Ref<ShardState>> fetch_block_state(BlockIdExt block_id) {
|
||||
Ref<vm::Cell> state_root = get_virt_state_root(block_id.root_hash);
|
||||
if (state_root.is_null()) {
|
||||
return td::Status::Error(PSTRING() << "cannot get hash of state root: " << block_id.to_str());
|
||||
}
|
||||
td::Bits256 state_root_hash = state_root->get_hash().bits();
|
||||
auto it = virt_roots_.find(state_root_hash);
|
||||
if (it == virt_roots_.end()) {
|
||||
return td::Status::Error(PSTRING() << "cannot get state root from collated data: " << block_id.to_str());
|
||||
}
|
||||
TRY_RESULT(res, ShardStateQ::fetch(block_id, {}, it->second));
|
||||
return Ref<ShardState>(res);
|
||||
}
|
||||
|
||||
void after_get_mc_state(td::Result<Ref<ShardState>> res);
|
||||
void after_get_shard_state(int idx, td::Result<Ref<ShardState>> res);
|
||||
bool process_mc_state(Ref<MasterchainState> mc_state);
|
||||
bool try_unpack_mc_state();
|
||||
bool fetch_config_params();
|
||||
bool check_prev_block(const BlockIdExt& listed, const BlockIdExt& prev, bool chk_chain_len = true);
|
||||
bool check_prev_block_exact(const BlockIdExt& listed, const BlockIdExt& prev);
|
||||
bool check_this_shard_mc_info();
|
||||
bool init_parse();
|
||||
bool unpack_block_candidate();
|
||||
bool extract_collated_data_from(Ref<vm::Cell> croot, int idx);
|
||||
bool extract_collated_data();
|
||||
bool try_validate();
|
||||
bool compute_prev_state();
|
||||
bool unpack_merge_prev_state();
|
||||
bool unpack_prev_state();
|
||||
bool init_next_state();
|
||||
bool unpack_one_prev_state(block::ShardState& ss, BlockIdExt blkid, Ref<vm::Cell> prev_state_root);
|
||||
bool split_prev_state(block::ShardState& ss);
|
||||
bool request_neighbor_queues();
|
||||
void got_neighbor_out_queue(int i, td::Result<Ref<MessageQueue>> res);
|
||||
|
||||
bool register_mc_state(Ref<MasterchainStateQ> other_mc_state);
|
||||
bool request_aux_mc_state(BlockSeqno seqno, Ref<MasterchainStateQ>& state);
|
||||
Ref<MasterchainStateQ> get_aux_mc_state(BlockSeqno seqno) const;
|
||||
void after_get_aux_shard_state(ton::BlockIdExt blkid, td::Result<Ref<ShardState>> res);
|
||||
|
||||
bool check_utime_lt();
|
||||
bool prepare_out_msg_queue_size();
|
||||
void got_out_queue_size(size_t i, td::Result<td::uint64> res);
|
||||
|
||||
bool fix_one_processed_upto(block::MsgProcessedUpto& proc, ton::ShardIdFull owner, bool allow_cur = false);
|
||||
bool fix_processed_upto(block::MsgProcessedUptoCollection& upto, bool allow_cur = false);
|
||||
bool fix_all_processed_upto();
|
||||
bool add_trivial_neighbor_after_merge();
|
||||
bool add_trivial_neighbor();
|
||||
bool unpack_block_data();
|
||||
bool unpack_precheck_value_flow(Ref<vm::Cell> value_flow_root);
|
||||
bool compute_minted_amount(block::CurrencyCollection& to_mint);
|
||||
bool postcheck_one_account_update(td::ConstBitPtr acc_id, Ref<vm::CellSlice> old_value, Ref<vm::CellSlice> new_value);
|
||||
bool postcheck_account_updates();
|
||||
bool precheck_one_transaction(td::ConstBitPtr acc_id, ton::LogicalTime trans_lt, Ref<vm::CellSlice> trans_csr,
|
||||
ton::Bits256& prev_trans_hash, ton::LogicalTime& prev_trans_lt,
|
||||
unsigned& prev_trans_lt_len, ton::Bits256& acc_state_hash);
|
||||
bool precheck_one_account_block(td::ConstBitPtr acc_id, Ref<vm::CellSlice> acc_blk);
|
||||
bool precheck_account_transactions();
|
||||
Ref<vm::Cell> lookup_transaction(const ton::StdSmcAddress& addr, ton::LogicalTime lt) const;
|
||||
bool is_valid_transaction_ref(Ref<vm::Cell> trans_ref) const;
|
||||
|
||||
bool build_new_message_queue();
|
||||
bool precheck_one_message_queue_update(td::ConstBitPtr out_msg_id, Ref<vm::CellSlice> old_value,
|
||||
Ref<vm::CellSlice> new_value);
|
||||
bool precheck_message_queue_update();
|
||||
bool check_account_dispatch_queue_update(td::Bits256 addr, Ref<vm::CellSlice> old_queue_csr,
|
||||
Ref<vm::CellSlice> new_queue_csr);
|
||||
bool unpack_dispatch_queue_update();
|
||||
bool update_max_processed_lt_hash(ton::LogicalTime lt, const ton::Bits256& hash);
|
||||
bool update_min_enqueued_lt_hash(ton::LogicalTime lt, const ton::Bits256& hash);
|
||||
bool check_imported_message(Ref<vm::Cell> msg_env);
|
||||
bool is_special_in_msg(const vm::CellSlice& in_msg) const;
|
||||
bool check_in_msg(td::ConstBitPtr key, Ref<vm::CellSlice> in_msg);
|
||||
bool check_in_msg_descr();
|
||||
bool check_out_msg(td::ConstBitPtr key, Ref<vm::CellSlice> out_msg);
|
||||
bool check_out_msg_descr();
|
||||
bool check_dispatch_queue_update();
|
||||
bool check_processed_upto();
|
||||
bool check_neighbor_outbound_message(Ref<vm::CellSlice> enq_msg, ton::LogicalTime lt, td::ConstBitPtr key,
|
||||
const block::McShardDescr& src_nb, bool& unprocessed, bool& processed_here,
|
||||
td::Bits256& msg_hash);
|
||||
bool check_in_queue();
|
||||
std::unique_ptr<block::Account> make_account_from(td::ConstBitPtr addr, Ref<vm::CellSlice> account);
|
||||
std::unique_ptr<block::Account> unpack_account(td::ConstBitPtr addr);
|
||||
bool check_one_transaction(block::Account& account, LogicalTime lt, Ref<vm::Cell> trans_root, bool is_first,
|
||||
bool is_last);
|
||||
bool check_account_transactions(const StdSmcAddress& acc_addr, Ref<vm::CellSlice> acc_tr);
|
||||
bool check_transactions();
|
||||
bool check_message_processing_order();
|
||||
bool check_new_state();
|
||||
bool postcheck_value_flow();
|
||||
|
||||
Ref<vm::Cell> get_virt_state_root(td::Bits256 block_root_hash);
|
||||
|
||||
td::BufferSlice result_state_update_;
|
||||
|
||||
bool store_master_ref(vm::CellBuilder& cb);
|
||||
bool build_state_update();
|
||||
};
|
||||
|
||||
} // namespace solution
|
17
contest/solution/solution.cpp
Normal file
17
contest/solution/solution.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include "solution.hpp"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "block-auto.h"
|
||||
#include "contest-validate-query.hpp"
|
||||
|
||||
void run_contest_solution(ton::BlockIdExt block_id, td::BufferSlice block_data, td::BufferSlice colldated_data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
TRY_RESULT_PROMISE(promise, root, vm::std_boc_deserialize(block_data));
|
||||
block::gen::Block::Record rec;
|
||||
if (!block::gen::t_Block.cell_unpack(root, rec)) {
|
||||
return promise.set_error(td::Status::Error("failed to unpack block"));
|
||||
}
|
||||
TRY_RESULT_PROMISE(promise, res, vm::std_boc_serialize(rec.state_update));
|
||||
td::actor::create_actor<solution::ContestValidateQuery>(
|
||||
"validate", block_id, std::move(block_data), std::move(colldated_data), std::move(promise)).release();
|
||||
}
|
6
contest/solution/solution.hpp
Normal file
6
contest/solution/solution.hpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
void run_contest_solution(ton::BlockIdExt block_id, td::BufferSlice block_data, td::BufferSlice colldated_data,
|
||||
td::Promise<td::BufferSlice> promise);
|
|
@ -1957,9 +1957,10 @@ bool unpack_block_prev_blk(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
|||
|
||||
td::Status unpack_block_prev_blk_try(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
||||
std::vector<ton::BlockIdExt>& prev, ton::BlockIdExt& mc_blkid, bool& after_split,
|
||||
ton::BlockIdExt* fetch_blkid) {
|
||||
ton::BlockIdExt* fetch_blkid, bool ignore_root_hash) {
|
||||
try {
|
||||
return unpack_block_prev_blk_ext(std::move(block_root), id, prev, mc_blkid, after_split, fetch_blkid);
|
||||
return unpack_block_prev_blk_ext(std::move(block_root), id, prev, mc_blkid, after_split, fetch_blkid,
|
||||
ignore_root_hash);
|
||||
} catch (vm::VmError err) {
|
||||
return td::Status::Error(std::string{"error while processing Merkle proof: "} + err.get_msg());
|
||||
} catch (vm::VmVirtError err) {
|
||||
|
@ -1969,7 +1970,7 @@ td::Status unpack_block_prev_blk_try(Ref<vm::Cell> block_root, const ton::BlockI
|
|||
|
||||
td::Status unpack_block_prev_blk_ext(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
||||
std::vector<ton::BlockIdExt>& prev, ton::BlockIdExt& mc_blkid, bool& after_split,
|
||||
ton::BlockIdExt* fetch_blkid) {
|
||||
ton::BlockIdExt* fetch_blkid, bool ignore_root_hash) {
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::ExtBlkRef::Record mcref; // _ ExtBlkRef = BlkMasterInfo;
|
||||
|
@ -1988,7 +1989,7 @@ td::Status unpack_block_prev_blk_ext(Ref<vm::Cell> block_root, const ton::BlockI
|
|||
if (id.id != hdr_id) {
|
||||
return td::Status::Error("block header contains block id "s + hdr_id.to_str() + ", expected " + id.id.to_str());
|
||||
}
|
||||
if (id.root_hash != block_root->get_hash().bits()) {
|
||||
if (id.root_hash != block_root->get_hash().bits() && !ignore_root_hash) {
|
||||
return td::Status::Error("block header has incorrect root hash "s + block_root->get_hash().bits().to_hex(256) +
|
||||
" instead of expected " + id.root_hash.to_hex());
|
||||
}
|
||||
|
|
|
@ -725,10 +725,10 @@ bool unpack_block_prev_blk(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
|||
ton::BlockIdExt& mc_blkid, bool& after_split, ton::BlockIdExt* fetch_blkid = nullptr);
|
||||
td::Status unpack_block_prev_blk_ext(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
||||
std::vector<ton::BlockIdExt>& prev, ton::BlockIdExt& mc_blkid, bool& after_split,
|
||||
ton::BlockIdExt* fetch_blkid = nullptr);
|
||||
ton::BlockIdExt* fetch_blkid = nullptr, bool ignore_root_hash = false);
|
||||
td::Status unpack_block_prev_blk_try(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
||||
std::vector<ton::BlockIdExt>& prev, ton::BlockIdExt& mc_blkid, bool& after_split,
|
||||
ton::BlockIdExt* fetch_blkid = nullptr);
|
||||
ton::BlockIdExt* fetch_blkid = nullptr, bool ignore_root_hash = false);
|
||||
td::Status check_block_header(Ref<vm::Cell> block_root, const ton::BlockIdExt& id,
|
||||
ton::Bits256* store_shard_hash_to = nullptr);
|
||||
|
||||
|
|
|
@ -473,6 +473,11 @@ block#11ef55aa global_id:int32
|
|||
state_update:^(MERKLE_UPDATE ShardState)
|
||||
extra:^BlockExtra = Block;
|
||||
|
||||
block_relaxed#11ef55aa global_id:int32
|
||||
info:^BlockInfo value_flow:^ValueFlow
|
||||
state_update:^Cell
|
||||
extra:^BlockExtra = BlockRelaxed;
|
||||
|
||||
block_extra in_msg_descr:^InMsgDescr
|
||||
out_msg_descr:^OutMsgDescr
|
||||
account_blocks:^ShardAccountBlocks
|
||||
|
@ -853,6 +858,7 @@ top_block_descr#d5 proof_for:BlockIdExt signatures:(Maybe ^BlockSignatures)
|
|||
// COLLATED DATA
|
||||
//
|
||||
top_block_descr_set#4ac789f3 collection:(HashmapE 96 ^TopBlockDescr) = TopBlockDescrSet;
|
||||
extra_collated_data#ea59be4c underload:Bool overload:Bool proc_info:ProcessedInfo = ExtraCollatedData;
|
||||
|
||||
//
|
||||
// VALIDATOR MISBEHAVIOR COMPLAINTS
|
||||
|
|
|
@ -1099,3 +1099,5 @@ storage.daemon.removeStorageProvider = storage.daemon.Success;
|
|||
|
||||
---types---
|
||||
proxyLiteserver.config port:int id:PublicKey = proxyLiteserver.Config;
|
||||
|
||||
contest.test block_id:tonNode.blockIdExt block_data:bytes collated_data:bytes valid:Bool = contest.Test;
|
||||
|
|
Binary file not shown.
Loading…
Reference in a new issue