diff --git a/test/fisherman/block_manipulator/header_corrupter.cpp b/test/fisherman/block_manipulator/header_corrupter.cpp index f019d070..5e5a1b6d 100644 --- a/test/fisherman/block_manipulator/header_corrupter.cpp +++ b/test/fisherman/block_manipulator/header_corrupter.cpp @@ -1,9 +1,34 @@ #include "header_corrupter.hpp" +#include "block/block-parse.h" +#include "block/block-auto.h" + namespace test::fisherman { -auto HeaderCorrupter::Config::fromJson(td::JsonValue jv) -> Config { - return Config{}; +HeaderCorrupter::Config HeaderCorrupter::Config::fromJson(td::JsonValue jv) { + Config cfg; + CHECK(jv.type() == td::JsonValue::Type::Object); + auto &obj = jv.get_object(); + + cfg.distort_timestamp = td::get_json_object_bool_field(obj, "distort_timestamp", true, false).move_as_ok(); + cfg.time_offset = td::get_json_object_int_field(obj, "time_offset", true, 999999999).move_as_ok(); + + cfg.mark_subshard_of_master = + td::get_json_object_bool_field(obj, "mark_subshard_of_master", true, false).move_as_ok(); + cfg.invert_lt = td::get_json_object_bool_field(obj, "invert_lt", true, false).move_as_ok(); + cfg.mark_keyblock_on_shard = td::get_json_object_bool_field(obj, "mark_keyblock_on_shard", true, false).move_as_ok(); + + cfg.force_after_merge_for_mc = td::get_json_object_bool_field(obj, "force_after_merge_for_mc", true, false).move_as_ok(); + cfg.force_before_split_for_mc = td::get_json_object_bool_field(obj, "force_before_split_for_mc", true, false).move_as_ok(); + cfg.force_after_split_for_mc = td::get_json_object_bool_field(obj, "force_after_split_for_mc", true, false).move_as_ok(); + cfg.allow_both_after_merge_and_split = + td::get_json_object_bool_field(obj, "allow_both_after_merge_and_split", true, false).move_as_ok(); + + cfg.shard_pfx_zero_yet_after_split = + td::get_json_object_bool_field(obj, "shard_pfx_zero_yet_after_split", true, false).move_as_ok(); + + cfg.set_vert_seqno_incr = td::get_json_object_bool_field(obj, "set_vert_seqno_incr", true, false).move_as_ok(); + return cfg; } HeaderCorrupter::HeaderCorrupter(Config config) : config_(std::move(config)) { @@ -11,11 +36,81 @@ HeaderCorrupter::HeaderCorrupter(Config config) : config_(std::move(config)) { void HeaderCorrupter::modify(block::gen::Block::Record &block) { block::gen::BlockInfo::Record info_rec; - bool ok = block::gen::BlockInfo().cell_unpack(block.info, info_rec); - CHECK(ok); - info_rec.after_merge = true; - info_rec.after_split = true; - block::gen::BlockInfo().cell_pack(block.info, info_rec); + CHECK(block::gen::t_BlockInfo.cell_unpack(block.info, info_rec)); + + // 1) distort_timestamp => сдвигаем info_rec.gen_utime + if (config_.distort_timestamp) { + info_rec.gen_utime += config_.time_offset; + } + + // 2) mark_subshard_of_master => если workchain == -1, делаем shard_pfx_bits != 0, то есть блок "подшард" MC + if (config_.mark_subshard_of_master) { + block::gen::ShardIdent::Record shard_rec; + CHECK(block::gen::ShardIdent().unpack(info_rec.shard.write(), shard_rec)); + CHECK(shard_rec.workchain_id == -1 && !info_rec.not_master); + if (shard_rec.shard_pfx_bits == 0) { + shard_rec.shard_pfx_bits = 10; + shard_rec.shard_prefix = 123456ULL; + } + vm::CellBuilder cb; + CHECK(block::gen::t_ShardIdent.pack(cb, shard_rec)); + info_rec.shard = td::Ref{true, cb.finalize()}; + } + + // 3) invert_lt => start_lt >= end_lt + if (config_.invert_lt) { + if (info_rec.start_lt < info_rec.end_lt) { + auto tmp = info_rec.start_lt; + info_rec.start_lt = info_rec.end_lt; + info_rec.end_lt = tmp; + } + } + + // 4) mark_keyblock_on_shard => если "not_master" = true, то проставим key_block = true + if (config_.mark_keyblock_on_shard) { + CHECK(info_rec.not_master); + info_rec.key_block = true; + } + + // 5) force_after_merge / force_before_split / force_after_split для MC + if (config_.force_after_merge_for_mc) { + CHECK(!info_rec.not_master); + info_rec.after_merge = true; + } + if (config_.force_before_split_for_mc) { + CHECK(!info_rec.not_master); + info_rec.before_split = true; + } + if (config_.force_after_split_for_mc) { + CHECK(!info_rec.not_master); + info_rec.after_split = true; + } + + // 6) allow_both_after_merge_and_split => ставим after_merge=1 и after_split=1 + if (config_.allow_both_after_merge_and_split) { + info_rec.after_merge = true; + info_rec.after_split = true; + } + + // 7) shard_pfx_zero_yet_after_split => shard_pfx_bits=0, after_split=1 + if (config_.shard_pfx_zero_yet_after_split) { + info_rec.after_split = true; + block::gen::ShardIdent::Record shard_rec; + CHECK(block::gen::ShardIdent().unpack(info_rec.shard.write(), shard_rec)); + shard_rec.shard_pfx_bits = 0; + vm::CellBuilder cb; + CHECK(block::gen::t_ShardIdent.pack(cb, shard_rec)); + info_rec.shard = td::Ref{true, cb.finalize()}; + } + + // 8) set_vert_seqno_incr => vert_seqno_incr != 0 => ставим true + if (config_.set_vert_seqno_incr) { + info_rec.vert_seq_no = 1; + info_rec.vert_seqno_incr = true; + info_rec.prev_vert_ref = info_rec.prev_ref; + } + + CHECK(block::gen::t_BlockInfo.cell_pack(block.info, info_rec)); } } // namespace test::fisherman diff --git a/test/fisherman/block_manipulator/header_corrupter.hpp b/test/fisherman/block_manipulator/header_corrupter.hpp index 1fe0f4a6..4978252d 100644 --- a/test/fisherman/block_manipulator/header_corrupter.hpp +++ b/test/fisherman/block_manipulator/header_corrupter.hpp @@ -1,20 +1,36 @@ #pragma once #include "base.hpp" + #include "td/utils/JsonBuilder.h" +#include "block/block-auto.h" namespace test::fisherman { class HeaderCorrupter : public BaseManipulator { public: struct Config { - // TODO: add corruption field and method + bool distort_timestamp = false; + td::int32 time_offset = 1'000'000'000; - static auto fromJson(td::JsonValue jv) -> Config; + bool mark_subshard_of_master = false; + bool invert_lt = false; + bool mark_keyblock_on_shard = false; + + bool force_after_merge_for_mc = false; + bool force_before_split_for_mc = false; + bool force_after_split_for_mc = false; + bool allow_both_after_merge_and_split = false; + + bool shard_pfx_zero_yet_after_split = false; + + bool set_vert_seqno_incr = false; + + static Config fromJson(td::JsonValue jv); }; explicit HeaderCorrupter(Config config); - void modify(block::gen::Block::Record &block) final; + void modify(block::gen::Block::Record &block) override; private: Config config_; diff --git a/test/fisherman/tests.cpp b/test/fisherman/tests.cpp index 4a7249c9..362d0c0a 100644 --- a/test/fisherman/tests.cpp +++ b/test/fisherman/tests.cpp @@ -6,6 +6,14 @@ using namespace test::fisherman; +void print_block(const block::gen::Block::Record &block_rec) { + std::ostringstream os; + td::Ref block_cell_pack; + CHECK(block::gen::t_Block.cell_pack(block_cell_pack, block_rec)); + block::gen::t_Block.print_ref(os, block_cell_pack); + LOG(INFO) << "Block = " << os.str(); +} + auto main(int argc, char **argv) -> int { if (argc < 3) { std::cerr << "Usage: " << argv[0] << " /path/to/rootdb config.json\n"; @@ -51,30 +59,17 @@ auto main(int argc, char **argv) -> int { } auto blk_data = blk_data_result.move_as_ok(); - LOG(INFO) << "BlockId: " << blk_data->block_id().to_str(); - LOG(INFO) << "Block data size: " << blk_data->data().size() << " bytes"; - - LOG(INFO) << "Cell has block record = " << block::gen::Block().validate_ref(10000000, blk_data->root_cell()) << "\n"; - - std::ostringstream os; - block::gen::Block().print_ref(os, blk_data->root_cell()); - LOG(INFO) << "Block = " << os.str(); block::gen::Block::Record block_rec; - bool ok = block::gen::Block().cell_unpack(blk_data->root_cell(), block_rec); - CHECK(ok); + CHECK(block::gen::t_Block.cell_unpack(blk_data->root_cell(), block_rec)); - block::gen::BlockInfo::Record info_rec; - block::gen::BlockInfo().cell_unpack(block_rec.info, info_rec); - LOG(INFO) << "Block.info after_merge=" << info_rec.after_merge << ", after_split=" << info_rec.after_split; + print_block(block_rec); auto manipulation_config = td::get_json_object_field(js_obj, "manipulation", td::JsonValue::Type::Object, false); CHECK(manipulation_config.is_ok()); ManipulatorFactory().create(manipulation_config.move_as_ok())->modify(block_rec); LOG(INFO) << "Block after manipulation:"; - block::gen::BlockInfo().cell_unpack(block_rec.info, info_rec); - LOG(INFO) << "Block.info after_merge=" << info_rec.after_merge << ", after_split=" << info_rec.after_split; - + print_block(block_rec); return 0; }