diff --git a/crypto/block/block.cpp b/crypto/block/block.cpp index 7b8074bf..80723b58 100644 --- a/crypto/block/block.cpp +++ b/crypto/block/block.cpp @@ -718,12 +718,9 @@ td::Status ShardState::unpack_state(ton::BlockIdExt blkid, Ref prev_st return td::Status::Error(-666, "shardchain state for "s + blkid.to_str() + " corresponds to incorrect workchain or shard " + shard1.to_str()); } - if (state.vert_seq_no) { - return td::Status::Error( - -666, "shardchain state for "s + blkid.to_str() + " has non-zero vert_seq_no, which is unsupported"); - } id_ = blkid; root_ = std::move(prev_state_root); + vert_seqno_ = state.vert_seq_no; before_split_ = state.before_split; account_dict_ = std::make_unique( vm::load_cell_slice(std::move(state.accounts)).prefetch_ref(), 256, block::tlb::aug_ShardAccounts); @@ -811,7 +808,7 @@ td::Status ShardState::unpack_out_msg_queue_info(Ref out_msg_queue_inf } out_msg_queue_ = std::make_unique(std::move(qinfo.out_queue), 352, block::tlb::aug_OutMsgQueue); - if (verbosity >= 3 * 0) { + if (verbosity >= 3 * 1) { LOG(DEBUG) << "unpacking ProcessedUpto of our previous block " << id_.to_str(); block::gen::t_ProcessedInfo.print(std::cerr, qinfo.proc_info); } @@ -953,14 +950,16 @@ td::Status ShardState::merge_with(ShardState& sib) { lt_ = std::max(lt_, sib.lt_); // 9. compute underload & overload history underload_history_ = overload_history_ = 0; + // 10. compute vert_seqno + vert_seqno_ = std::max(vert_seqno_, sib.vert_seqno_); // Anything else? add here // ... - // 10. compute new root + // 100. compute new root if (!block::gen::t_ShardState.cell_pack_split_state(root_, std::move(root_), std::move(sib.root_))) { return td::Status::Error(-667, "cannot construct a virtual split_state after a merge"); } - // 11. invalidate sibling, change id_ to the (virtual) common parent + // 101. invalidate sibling, change id_ to the (virtual) common parent sib.invalidate(); id_.id.shard = shard.shard; id_.file_hash.set_zero(); diff --git a/crypto/block/block.h b/crypto/block/block.h index 9fbeedf2..604036d0 100644 --- a/crypto/block/block.h +++ b/crypto/block/block.h @@ -384,7 +384,7 @@ struct ShardState { int global_id_; ton::UnixTime utime_; ton::LogicalTime lt_; - ton::BlockSeqno mc_blk_seqno_, min_ref_mc_seqno_; + ton::BlockSeqno mc_blk_seqno_, min_ref_mc_seqno_, vert_seqno_; ton::BlockIdExt mc_blk_ref_; ton::LogicalTime mc_blk_lt_; bool before_split_{false}; diff --git a/crypto/block/mc-config.h b/crypto/block/mc-config.h index dc48ec02..24351c0c 100644 --- a/crypto/block/mc-config.h +++ b/crypto/block/mc-config.h @@ -556,7 +556,7 @@ class ConfigInfo : public Config, public ShardConfig { needAccountsRoot = 64, needPrevBlocks = 128 }; - int vert_seqno{-1}; + ton::BlockSeqno vert_seqno{~0U}; int global_id_{0}; ton::UnixTime utime{0}; ton::LogicalTime lt{0}; @@ -604,6 +604,9 @@ class ConfigInfo : public Config, public ShardConfig { Ref get_state_extra_root() const { return state_extra_root_; } + ton::BlockSeqno get_vert_seqno() const { + return vert_seqno; + } ton::CatchainSeqno get_shard_cc_seqno(ton::ShardIdFull shard) const; bool get_last_key_block(ton::BlockIdExt& blkid, ton::LogicalTime& blklt, bool strict = false) const; bool get_old_mc_block_id(ton::BlockSeqno seqno, ton::BlockIdExt& blkid, ton::LogicalTime* end_lt = nullptr) const; diff --git a/crypto/func/codegen.cpp b/crypto/func/codegen.cpp index 7e0d873f..6aa196c1 100644 --- a/crypto/func/codegen.cpp +++ b/crypto/func/codegen.cpp @@ -308,7 +308,7 @@ bool Op::generate_code_step(Stack& stack) { func->compile(stack.o, res, args); // compile res := f (args) } else { std::string name = sym::symbols.get_name(fun_ref->sym_idx); - stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size()); + stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size()); } stack.push_new_var(left[0]); return true; @@ -395,7 +395,7 @@ bool Op::generate_code_step(Stack& stack) { assert(stack.s[k + i].first == right1[i]); } if (cl == _CallInd) { - stack.o << exec_arg_op("CALLARGS", (int)right.size() - 1, -1, (int)right.size() - 1); + stack.o << exec_arg_op("CALLARGS", (int)right.size() - 1, (int)right.size(), (int)left.size()); } else { auto func = dynamic_cast(fun_ref->value); if (func) { @@ -407,7 +407,7 @@ bool Op::generate_code_step(Stack& stack) { func->compile(stack.o, res, args); // compile res := f (args) } else { std::string name = sym::symbols.get_name(fun_ref->sym_idx); - stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size()); + stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size()); } } stack.s.resize(k); @@ -421,6 +421,11 @@ bool Op::generate_code_step(Stack& stack) { if (block0->is_empty() && block1->is_empty()) { return true; } + if (!next->noreturn() && (block0->noreturn() != block1->noreturn())) { + // simple fix of unbalanced returns in if/else branches + // (to be replaced with a finer condition working in loop bodies) + throw src::ParseError{where, "`if` and `else` branches should both return or both not return"}; + } var_idx_t x = left[0]; stack.rearrange_top(x, var_info[x] && var_info[x]->is_last()); assert(stack[0] == x); diff --git a/validator/impl/collator-impl.h b/validator/impl/collator-impl.h index bff46e17..586c9e8b 100644 --- a/validator/impl/collator-impl.h +++ b/validator/impl/collator-impl.h @@ -129,6 +129,7 @@ class Collator final : public td::actor::Actor { ton::UnixTime prev_state_utime_; int global_id_{0}; ton::BlockSeqno min_ref_mc_seqno_{~0U}; + ton::BlockSeqno vert_seqno_{~0U}, prev_vert_seqno_{~0U}; ton::BlockIdExt prev_key_block_; ton::LogicalTime prev_key_block_lt_; bool accept_msgs_{true}; diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 269b13e1..3f7983b2 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -518,6 +518,8 @@ bool Collator::unpack_last_mc_state() { prev_key_block_seqno_ = 0; } LOG(DEBUG) << "previous key block is " << prev_key_block_.to_str() << " (exists=" << prev_key_block_exists_ << ")"; + vert_seqno_ = config_->get_vert_seqno(); + LOG(DEBUG) << "vertical seqno (vert_seqno) is " << vert_seqno_; auto limits = config_->get_block_limits(is_masterchain()); if (limits.is_error()) { return fatal_error(limits.move_as_error()); @@ -686,6 +688,12 @@ bool Collator::unpack_one_last_state(block::ShardState& ss, BlockIdExt blkid, Re if (res.is_error()) { return fatal_error(std::move(res)); } + if (ss.vert_seqno_ > vert_seqno_) { + return fatal_error( + PSTRING() << "cannot create new block with vertical seqno " << vert_seqno_ + << " prescribed by the current masterchain configuration because the previous state of shard " + << ss.id_.to_str() << " has larger vertical seqno " << ss.vert_seqno_); + } return true; } @@ -712,8 +720,8 @@ bool Collator::split_last_state(block::ShardState& ss) { // SETS: account_dict, shard_libraries_, mc_state_extra // total_balance_ = old_total_balance_, total_validator_fees_ -// SETS: overload_history, underload_history -// SETS: prev_state_utime_, prev_state_lt_ +// SETS: overload_history_, underload_history_ +// SETS: prev_state_utime_, prev_state_lt_, prev_vert_seqno_ // SETS: out_msg_queue, processed_upto_, ihr_pending bool Collator::import_shard_state_data(block::ShardState& ss) { account_dict = std::move(ss.account_dict_); @@ -723,6 +731,7 @@ bool Collator::import_shard_state_data(block::ShardState& ss) { underload_history_ = ss.underload_history_; prev_state_utime_ = ss.utime_; prev_state_lt_ = ss.lt_; + prev_vert_seqno_ = ss.vert_seqno_; total_balance_ = old_total_balance_ = std::move(ss.total_balance_); value_flow_.from_prev_blk = old_total_balance_; total_validator_fees_ = std::move(ss.total_validator_fees_); @@ -3426,7 +3435,7 @@ bool Collator::create_shard_state() { && global_id_ // { global_id != 0 } && block::ShardId{shard}.serialize(cb) // shard_id:ShardIdent && cb.store_long_bool(new_block_seqno, 32) // seq_no:uint32 - && cb.store_long_bool(0, 32) // vert_seq_no:# + && cb.store_long_bool(vert_seqno_, 32) // vert_seq_no:# && cb.store_long_bool(now_, 32) // gen_utime:uint32 && cb.store_long_bool(max_lt, 64) // gen_lt:uint64 && update_processed_upto() // insert new ProcessedUpto @@ -3561,9 +3570,9 @@ bool Collator::create_block_info(Ref& block_info) { && cb.store_bool_bool(want_split_) // want_split:Bool && cb.store_bool_bool(want_merge_) // want_merge:Bool && cb.store_bool_bool(is_key_block_) // key_block:Bool - && cb.store_long_bool(0, 9) // flags:(## 9) + && cb.store_long_bool(0, 9) // vert_seqno_incr:(## 1) flags:(## 8) && cb.store_long_bool(new_block_seqno, 32) // seq_no:# - && cb.store_long_bool(0, 32) // vert_seq_no:# + && cb.store_long_bool(vert_seqno_, 32) // vert_seq_no:# && block::ShardId{shard}.serialize(cb) // shard:ShardIdent && cb.store_long_bool(now_, 32) // gen_utime:uint32 && cb.store_long_bool(start_lt, 64) // start_lt:uint64 diff --git a/validator/impl/top-shard-descr.cpp b/validator/impl/top-shard-descr.cpp index 6050779d..e4c1328b 100644 --- a/validator/impl/top-shard-descr.cpp +++ b/validator/impl/top-shard-descr.cpp @@ -100,6 +100,7 @@ td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref ShardTopBlockDescrQ::validate_internal(BlockIdExt last_mc_block_ BlockSeqno delta = chain_mc_blk_ids_[0].id.seqno - last_mc_block_id.id.seqno; // too new if ((mode & Mode::fail_new) || (delta > 8 && (mode & Mode::fail_too_new))) { - return td::Status::Error(-666, std::string{"ShardTopBlockDescr for "} + block_id_.to_str() + + return td::Status::Error(-666, "ShardTopBlockDescr for "s + block_id_.to_str() + " is too new for us: it refers to masterchain block " + chain_mc_blk_ids_[0].id.to_str() + " but we know only " + last_mc_block_id.to_str()); @@ -289,6 +295,18 @@ td::Result ShardTopBlockDescrQ::validate_internal(BlockIdExt last_mc_block_ return -1; // valid, but too new } auto config = state->get_config(); + if (config->get_vert_seqno() != vert_seqno_) { + if (vert_seqno_ < config->get_vert_seqno()) { + return td::Status::Error(-666, PSTRING() << "ShardTopBlockDescr for " << block_id_.to_str() + << " is too old: it has vertical seqno " << vert_seqno_ + << " but we already know about " << config->get_vert_seqno()); + } + if (mode & Mode::fail_new) { + return td::Status::Error(-666, PSTRING() << "ShardTopBlockDescr for " << block_id_.to_str() + << " is too new for us: it has vertical seqno " << vert_seqno_ + << " but we know only about " << config->get_vert_seqno()); + } + } BlockSeqno next_mc_seqno = ~BlockSeqno(0); for (const auto& mcid : chain_mc_blk_ids_) { if (mcid.id.seqno > next_mc_seqno) { diff --git a/validator/impl/top-shard-descr.hpp b/validator/impl/top-shard-descr.hpp index 8a82f096..c2e9cccc 100644 --- a/validator/impl/top-shard-descr.hpp +++ b/validator/impl/top-shard-descr.hpp @@ -89,6 +89,9 @@ class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase { Ref get_root() const { return root_; } + BlockSeqno get_vert_seqno() const { + return vert_seqno_; + } ShardTopBlockDescrQ(td::BufferSlice data, bool is_fake = false) : ShardTopBlockDescrQBase(std::move(data)), is_fake_(is_fake) { } @@ -123,6 +126,7 @@ class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase { UnixTime gen_utime_{0}; CatchainSeqno catchain_seqno_{0}; td::uint32 validator_set_hash_{0}; + BlockSeqno vert_seqno_{~0U}; td::uint32 sig_count_; ValidatorWeight sig_weight_; Ref sig_root_; diff --git a/validator/impl/validate-query.cpp b/validator/impl/validate-query.cpp index 19892874..2350d171 100644 --- a/validator/impl/validate-query.cpp +++ b/validator/impl/validate-query.cpp @@ -378,7 +378,7 @@ bool ValidateQuery::init_parse() { block::gen::ExtBlkRef::Record mcref; // _ ExtBlkRef = BlkMasterInfo; ShardIdFull shard; if (!(tlb::unpack_cell(block_root_, blk) && tlb::unpack_cell(blk.info, info) && !info.version && - block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no && + block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && block::gen::BlkPrevInfo{info.after_merge}.validate_ref(info.prev_ref) && (!info.not_master || tlb::unpack_cell(info.master_ref, mcref)) && tlb::unpack_cell(blk.extra, extra))) { return reject_query("cannot unpack block header"); @@ -393,6 +393,7 @@ bool ValidateQuery::init_parse() { return fatal_error("invalid Merkle update in block"); } global_id_ = blk.global_id; + vert_seqno_ = info.vert_seq_no; prev_state_hash_ = upd_cs.prefetch_ref(0)->get_hash(0).bits(); state_hash_ = upd_cs.prefetch_ref(1)->get_hash(0).bits(); start_lt_ = info.start_lt; @@ -428,6 +429,9 @@ bool ValidateQuery::init_parse() { if (is_key_block_ && !shard.is_masterchain()) { return reject_query("a non-masterchain block cannot be a key block"); } + if (info.vert_seqno_incr) { + return reject_query("new blocks cannot have vert_seqno_incr set"); + } if (info.after_merge != after_merge_) { return reject_query("after_merge value mismatch in block header"); } @@ -683,7 +687,13 @@ bool ValidateQuery::try_unpack_mc_state() { CHECK(!mc_seqno_ || new_shard_conf_->get_mc_hash().not_null()); } if (global_id_ != config_->get_global_blockchain_id()) { - return reject_query("blockchain global id mismatch"); + return reject_query(PSTRING() << "blockchain global id mismatch: new block has " << global_id_ + << " while the masterchain configuration expects " + << config_->get_global_blockchain_id()); + } + if (vert_seqno_ != config_->get_vert_seqno()) { + return reject_query(PSTRING() << "vertical seqno mismatch: new block has " << vert_seqno_ + << " while the masterchain configuration expects " << config_->get_vert_seqno()); } prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_); if (prev_key_block_exists_) { @@ -1102,6 +1112,10 @@ bool ValidateQuery::unpack_one_prev_state(block::ShardState& ss, BlockIdExt blki if (res.is_error()) { return fatal_error(std::move(res)); } + if (ss.vert_seqno_ > vert_seqno_) { + return reject_query(PSTRING() << "one of previous states " << ss.id_.to_str() << " has vertical seqno " + << ss.vert_seqno_ << " larger than that of the new block " << vert_seqno_); + } return true; } @@ -1148,6 +1162,10 @@ bool ValidateQuery::unpack_next_state() { return reject_query("new state refers to masterchain block "s + ns_.mc_blk_ref_.to_str() + " different from " + mc_blkid_.to_str() + " indicated in block header"); } + if (ns_.vert_seqno_ != vert_seqno_) { + return reject_query(PSTRING() << "new state has vertical seqno " << ns_.vert_seqno_ << " different from " + << vert_seqno_ << " declared in the new block header"); + } // ... return true; } diff --git a/validator/impl/validate-query.hpp b/validator/impl/validate-query.hpp index 14e40957..ed3f3810 100644 --- a/validator/impl/validate-query.hpp +++ b/validator/impl/validate-query.hpp @@ -176,6 +176,7 @@ class ValidateQuery : public td::actor::Actor { 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_;