mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated block header
1. Updated block header, proofs now contain more data Notice, that old proofs may become invalid in the future 2. Fixed message routing 3. Fixed block creator id in block header 4. Support for full proofs in tonlib 5. Support for partial state download 6. Some other bugfixes
This commit is contained in:
parent
bce33f588a
commit
13140ddf29
73 changed files with 2084 additions and 304 deletions
|
@ -88,13 +88,14 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
auto usage_cell = vm::UsageCell::create(block_root_, usage_tree->root_ptr());
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::ExtBlkRef::Record mcref{}; // _ ExtBlkRef = BlkMasterInfo;
|
||||
block::CurrencyCollection fees;
|
||||
ShardIdFull shard;
|
||||
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no &&
|
||||
block::gen::BlkPrevInfo{info.after_merge}.validate_ref(info.prev_ref) &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
tlb::unpack_cell(std::move(blk.extra), extra) && block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
(!info.not_master || tlb::unpack_cell(info.master_ref, mcref)))) {
|
||||
return fatal_error("cannot unpack block header");
|
||||
}
|
||||
|
@ -126,10 +127,9 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
}
|
||||
// 4. visit validator-set related fields in key blocks
|
||||
if (is_key_block_) {
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
mc_extra.key_block && mc_extra.config.not_null())) {
|
||||
if (!(tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && mc_extra.key_block &&
|
||||
mc_extra.config.not_null())) {
|
||||
return fatal_error("cannot unpack extra header of key masterchain block "s + blk_id.to_str());
|
||||
}
|
||||
auto cfg = block::Config::unpack_config(std::move(mc_extra.config));
|
||||
|
@ -156,10 +156,8 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
mc_blkid_.root_hash = mcref.root_hash;
|
||||
mc_blkid_.file_hash = mcref.file_hash;
|
||||
} else if (!is_key_block_) {
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
!mc_extra.key_block)) {
|
||||
if (!(tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && !mc_extra.key_block)) {
|
||||
return fatal_error("extra header of non-key masterchain block "s + blk_id.to_str() +
|
||||
" is invalid or contains extra information reserved for key blocks only");
|
||||
}
|
||||
|
@ -332,8 +330,8 @@ void AcceptBlockQuery::written_block_data() {
|
|||
if (is_fake_) {
|
||||
signatures_ = Ref<BlockSignatureSetQ>(create_signature_set(std::vector<BlockSignature>{}));
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_signatures, handle_, signatures_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_signatures, handle_,
|
||||
signatures_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_signatures);
|
||||
});
|
||||
|
@ -367,8 +365,8 @@ void AcceptBlockQuery::written_block_info() {
|
|||
td::actor::send_closure(manager_, &ValidatorManager::wait_prev_block_state, handle_, priority(), timeout_,
|
||||
std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, priority(), timeout_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, priority(),
|
||||
timeout_, [SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_block_data,
|
||||
R.move_as_ok());
|
||||
|
@ -408,8 +406,8 @@ void AcceptBlockQuery::got_prev_state(td::Ref<ShardState> state) {
|
|||
|
||||
handle_->set_split(state_->before_split());
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, state_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_,
|
||||
state_, [SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_state, R.move_as_ok());
|
||||
});
|
||||
|
@ -481,8 +479,8 @@ void AcceptBlockQuery::got_last_mc_block(std::pair<td::Ref<MasterchainState>, Bl
|
|||
if (last_mc_id_.id.seqno < mc_blkid_.id.seqno) {
|
||||
VLOG(VALIDATOR_DEBUG) << "shardchain block refers to newer masterchain block " << mc_blkid_.to_str()
|
||||
<< ", trying to obtain it";
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(), timeout_,
|
||||
[SelfId = actor_id(this)](td::Result<Ref<ShardState>> R) {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(),
|
||||
timeout_, [SelfId = actor_id(this)](td::Result<Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_mc_state,
|
||||
R.move_as_ok());
|
||||
|
@ -588,7 +586,7 @@ void AcceptBlockQuery::require_proof_link(BlockIdExt id) {
|
|||
CHECK(ton::ShardIdFull(id) == ton::ShardIdFull(id_));
|
||||
CHECK(id.id.seqno == id_.id.seqno - 1 - proof_links_.size());
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_proof_link_short, id, timeout_,
|
||||
[SelfId = actor_id(this), id](td::Result<Ref<ProofLink>> R) {
|
||||
[ SelfId = actor_id(this), id ](td::Result<Ref<ProofLink>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_proof_link, id,
|
||||
R.move_as_ok());
|
||||
|
@ -647,9 +645,15 @@ bool AcceptBlockQuery::unpack_proof_link(BlockIdExt id, Ref<ProofLink> proof_lin
|
|||
}
|
||||
try {
|
||||
block::gen::Block::Record block;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
if (!(tlb::unpack_cell(virt_root, block) && block::gen::t_ValueFlow.force_validate_ref(block.value_flow))) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() + " does not contain value flow information");
|
||||
}
|
||||
/* TEMP (uncomment later)
|
||||
if (!tlb::unpack_cell(std::move(block.extra), extra)) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() + " does not contain BlockExtra information");
|
||||
}
|
||||
*/
|
||||
} catch (vm::VmError& err) {
|
||||
return fatal_error("error unpacking proof link for block "s + id.to_str() + " : " + err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
|
|
|
@ -218,12 +218,19 @@ bool CheckProof::init_parse(bool is_aux) {
|
|||
if (is_key_block_ && !shard.is_masterchain()) {
|
||||
return fatal_error("a non-masterchain block cannot be a key block");
|
||||
}
|
||||
block::gen::BlockExtra::Record extra;
|
||||
if (!is_aux) {
|
||||
/* FIXME: temp (uncommend later)
|
||||
if (!tlb::unpack_cell(std::move(blk.extra), extra)) {
|
||||
return fatal_error("cannot unpack extra header of block "s + blk_id.to_str());
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (is_key_block_ && !is_aux) {
|
||||
// visit validator-set related fields in key blocks
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
mc_extra.key_block && mc_extra.config.not_null())) {
|
||||
if (!(tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && mc_extra.key_block &&
|
||||
mc_extra.config.not_null())) {
|
||||
return fatal_error("cannot unpack extra header of key masterchain block "s + blk_id.to_str());
|
||||
}
|
||||
auto cfg = block::Config::unpack_config(std::move(mc_extra.config));
|
||||
|
|
|
@ -55,12 +55,13 @@ class Collator final : public td::actor::Actor {
|
|||
bool block_full_{false};
|
||||
bool inbound_queues_empty_{false};
|
||||
bool libraries_changed_{false};
|
||||
bool prev_key_block_exists_{false};
|
||||
UnixTime min_ts;
|
||||
BlockIdExt min_mc_block_id;
|
||||
std::vector<BlockIdExt> prev_blocks;
|
||||
std::vector<Ref<ShardState>> prev_states;
|
||||
std::vector<Ref<BlockData>> prev_block_data;
|
||||
td::Bits256 created_by;
|
||||
Ed25519_PublicKey created_by_;
|
||||
Ref<ValidatorSet> validator_set;
|
||||
td::actor::ActorId<ValidatorManager> manager;
|
||||
td::Timestamp timeout;
|
||||
|
@ -78,7 +79,7 @@ class Collator final : public td::actor::Actor {
|
|||
|
||||
public:
|
||||
Collator(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
Ref<ValidatorSet> validator_set, td::Bits256 collator_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockCandidate> promise);
|
||||
~Collator() override = default;
|
||||
bool is_busy() const {
|
||||
|
@ -132,13 +133,15 @@ class Collator final : public td::actor::Actor {
|
|||
ton::LogicalTime prev_key_block_lt_;
|
||||
bool accept_msgs_{true};
|
||||
bool shard_conf_adjusted_{false};
|
||||
bool ihr_enabled_{false};
|
||||
bool create_stats_enabled_{false};
|
||||
td::uint64 overload_history_{0}, underload_history_{0};
|
||||
td::uint64 block_size_estimate_{};
|
||||
Ref<block::WorkchainInfo> wc_info_;
|
||||
std::vector<Ref<ShardTopBlockDescription>> shard_block_descr_;
|
||||
std::vector<Ref<ShardTopBlockDescrQ>> used_shard_block_descr_;
|
||||
std::unique_ptr<vm::Dictionary> shard_libraries_;
|
||||
Ref<vm::Cell> mc_state_extra;
|
||||
Ref<vm::Cell> mc_state_extra_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> account_dict;
|
||||
std::map<ton::StdSmcAddress, std::unique_ptr<block::Account>> accounts;
|
||||
std::vector<block::StoragePrices> storage_prices_;
|
||||
|
@ -162,6 +165,9 @@ class Collator final : public td::actor::Actor {
|
|||
std::unique_ptr<vm::AugmentedDictionary> in_msg_dict, out_msg_dict, out_msg_queue_, sibling_out_msg_queue_;
|
||||
std::unique_ptr<vm::Dictionary> ihr_pending;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> processed_upto_, sibling_processed_upto_;
|
||||
std::unique_ptr<vm::Dictionary> block_create_stats_;
|
||||
std::map<td::Bits256, int> block_create_count_;
|
||||
unsigned block_create_total_{0};
|
||||
std::vector<ExtMessage::Hash> bad_ext_msgs_, delay_ext_msgs_;
|
||||
Ref<vm::Cell> shard_account_blocks_; // ShardAccountBlocks
|
||||
std::vector<Ref<vm::Cell>> collated_roots_;
|
||||
|
@ -200,6 +206,7 @@ class Collator final : public td::actor::Actor {
|
|||
const block::CurrencyCollection& created);
|
||||
bool store_shard_fees(Ref<block::McShardHash> descr);
|
||||
bool import_new_shard_top_blocks();
|
||||
bool register_shard_block_creators(std::vector<td::Bits256> creator_list);
|
||||
bool init_block_limits();
|
||||
bool compute_minted_amount(block::CurrencyCollection& to_mint);
|
||||
bool init_value_create();
|
||||
|
@ -264,6 +271,9 @@ class Collator final : public td::actor::Actor {
|
|||
bool add_public_library(td::ConstBitPtr key, td::ConstBitPtr addr, Ref<vm::Cell> library);
|
||||
bool remove_public_library(td::ConstBitPtr key, td::ConstBitPtr addr);
|
||||
bool check_block_overload();
|
||||
bool update_block_creator_count(td::ConstBitPtr key, unsigned shard_incr, unsigned mc_incr);
|
||||
int creator_count_outdated(td::ConstBitPtr key, vm::CellSlice& cs);
|
||||
bool update_block_creator_stats();
|
||||
bool create_mc_state_extra();
|
||||
bool create_shard_state();
|
||||
td::Result<Ref<vm::Cell>> get_config_data_from_smc(const ton::StdSmcAddress& cfg_addr);
|
||||
|
|
|
@ -54,14 +54,14 @@ static inline bool dbg(int c) {
|
|||
}
|
||||
|
||||
Collator::Collator(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set, td::Bits256 collator_id,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise)
|
||||
: shard(shard)
|
||||
, min_ts(min_ts)
|
||||
, min_mc_block_id{min_masterchain_block_id}
|
||||
, prev_blocks(std::move(prev))
|
||||
, created_by(collator_id)
|
||||
, created_by_(collator_id)
|
||||
, validator_set(std::move(validator_set))
|
||||
, manager(manager)
|
||||
, timeout(timeout)
|
||||
|
@ -74,6 +74,10 @@ void Collator::start_up() {
|
|||
if (prev_blocks.size() > 1) {
|
||||
LOG(DEBUG) << "Previous block #2 is " << prev_blocks.at(1).to_str();
|
||||
}
|
||||
//if (created_by_.is_zero()) {
|
||||
// !!FIXME!! remove this debug later
|
||||
//td::as<td::uint32>(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
|
||||
//}
|
||||
// 1. check validity of parameters, especially prev_blocks, shard and min_mc_block_id
|
||||
if (shard.workchain != ton::masterchainId && shard.workchain != ton::basechainId) {
|
||||
fatal_error(-667, "can create block candidates only for masterchain (-1) and base workchain (0)");
|
||||
|
@ -161,12 +165,12 @@ void Collator::start_up() {
|
|||
// 2. learn latest masterchain state and block id
|
||||
LOG(DEBUG) << "sending get_top_masterchain_state_block() to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::get_top_masterchain_state_block,
|
||||
[self = get_self()](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res)->void {
|
||||
LOG(DEBUG) << "got answer to get_top_masterchain_state_block";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_mc_state, std::move(res));
|
||||
});
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_top_masterchain_state_block,
|
||||
[self = get_self()](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||
LOG(DEBUG) << "got answer to get_top_masterchain_state_block";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_mc_state,
|
||||
std::move(res));
|
||||
});
|
||||
}
|
||||
// 3. load previous block(s) and corresponding state(s)
|
||||
prev_states.resize(prev_blocks.size());
|
||||
|
@ -176,7 +180,7 @@ void Collator::start_up() {
|
|||
LOG(DEBUG) << "sending wait_block_state() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_blocks[i], priority(),
|
||||
timeout, [ self = get_self(), i ](td::Result<Ref<ShardState>> res) {
|
||||
timeout, [self = get_self(), i](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state query #" << i;
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_shard_state, i,
|
||||
std::move(res));
|
||||
|
@ -187,7 +191,7 @@ void Collator::start_up() {
|
|||
LOG(DEBUG) << "sending wait_block_data() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, prev_blocks[i], priority(),
|
||||
timeout, [ self = get_self(), i ](td::Result<Ref<BlockData>> res) {
|
||||
timeout, [self = get_self(), i](td::Result<Ref<BlockData>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_data query #" << i;
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_block_data, i,
|
||||
std::move(res));
|
||||
|
@ -197,8 +201,8 @@ void Collator::start_up() {
|
|||
// 4. load external messages
|
||||
LOG(DEBUG) << "sending get_external_messages() query to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_external_messages,
|
||||
shard, [self = get_self()](td::Result<std::vector<Ref<ExtMessage>>> res)->void {
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_external_messages, shard,
|
||||
[self = get_self()](td::Result<std::vector<Ref<ExtMessage>>> res) -> void {
|
||||
LOG(DEBUG) << "got answer to get_external_messages() query";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_external_messages,
|
||||
std::move(res));
|
||||
|
@ -208,8 +212,8 @@ void Collator::start_up() {
|
|||
LOG(DEBUG) << "sending get_shard_blocks() query to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::get_shard_blocks,
|
||||
prev_blocks[0], [self = get_self()](td::Result<std::vector<Ref<ShardTopBlockDescription>>> res)->void {
|
||||
manager, &ValidatorManager::get_shard_blocks, prev_blocks[0],
|
||||
[self = get_self()](td::Result<std::vector<Ref<ShardTopBlockDescription>>> res) -> void {
|
||||
LOG(DEBUG) << "got answer to get_shard_blocks() query";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_shard_blocks, std::move(res));
|
||||
});
|
||||
|
@ -326,7 +330,7 @@ bool Collator::request_aux_mc_state(BlockSeqno seqno, Ref<MasterchainStateQ>& st
|
|||
LOG(DEBUG) << "sending auxiliary wait_block_state() query for " << blkid.to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, blkid, priority(), timeout,
|
||||
[ self = get_self(), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
[self = get_self(), blkid](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state query for " << blkid.to_str();
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_aux_shard_state,
|
||||
blkid, std::move(res));
|
||||
|
@ -414,8 +418,8 @@ void Collator::after_get_mc_state(td::Result<std::pair<Ref<MasterchainState>, Bl
|
|||
// NB. it is needed only for creating a correct ExtBlkRef reference to it, which requires start_lt and end_lt
|
||||
LOG(DEBUG) << "sending wait_block_data() query #-1 for " << mc_block_id_.to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, mc_block_id_, priority(),
|
||||
timeout, [self = get_self()](td::Result<Ref<BlockData>> res) {
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, mc_block_id_, priority(), timeout,
|
||||
[self = get_self()](td::Result<Ref<BlockData>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_data query #-1";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_block_data, -1,
|
||||
std::move(res));
|
||||
|
@ -497,7 +501,7 @@ bool Collator::unpack_last_mc_state() {
|
|||
auto res = block::ConfigInfo::extract_config(
|
||||
mc_state_root,
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needLibraries | block::ConfigInfo::needValidatorSet |
|
||||
block::ConfigInfo::needWorkchainInfo |
|
||||
block::ConfigInfo::needWorkchainInfo | block::ConfigInfo::needCapabilities |
|
||||
(is_masterchain() ? block::ConfigInfo::needAccountsRoot | block::ConfigInfo::needSpecialSmc : 0));
|
||||
if (res.is_error()) {
|
||||
td::Status err = res.move_as_error();
|
||||
|
@ -506,16 +510,18 @@ bool Collator::unpack_last_mc_state() {
|
|||
}
|
||||
config_ = res.move_as_ok();
|
||||
CHECK(config_);
|
||||
if (prev_mc_block_seqno > 0) {
|
||||
config_->set_block_id_ext(mc_block_id_);
|
||||
}
|
||||
config_->set_block_id_ext(mc_block_id_);
|
||||
global_id_ = config_->get_global_blockchain_id();
|
||||
ihr_enabled_ = config_->ihr_enabled();
|
||||
create_stats_enabled_ = config_->create_stats_enabled();
|
||||
shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
if (config_->get_last_key_block(prev_key_block_, prev_key_block_lt_)) {
|
||||
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
|
||||
if (prev_key_block_exists_) {
|
||||
prev_key_block_seqno_ = prev_key_block_.seqno();
|
||||
} else {
|
||||
prev_key_block_seqno_ = 0;
|
||||
}
|
||||
LOG(DEBUG) << "previous key block is " << prev_key_block_.to_str() << " (exists=" << prev_key_block_exists_ << ")";
|
||||
auto limits = config_->get_block_limits(is_masterchain());
|
||||
if (limits.is_error()) {
|
||||
return fatal_error(limits.move_as_error());
|
||||
|
@ -552,7 +558,7 @@ bool Collator::request_neighbor_msg_queues() {
|
|||
LOG(DEBUG) << "neighbor #" << i << " : " << descr.blk_.to_str();
|
||||
++pending;
|
||||
send_closure_later(manager, &ValidatorManager::wait_block_message_queue_short, descr.blk_, priority(), timeout,
|
||||
[ self = get_self(), i ](td::Result<Ref<MessageQueue>> res) {
|
||||
[self = get_self(), i](td::Result<Ref<MessageQueue>> res) {
|
||||
td::actor::send_closure(std::move(self), &Collator::got_neighbor_out_queue, i, std::move(res));
|
||||
});
|
||||
++i;
|
||||
|
@ -716,7 +722,7 @@ bool Collator::split_last_state(block::ShardState& ss) {
|
|||
bool Collator::import_shard_state_data(block::ShardState& ss) {
|
||||
account_dict = std::move(ss.account_dict_);
|
||||
shard_libraries_ = std::move(ss.shard_libraries_);
|
||||
mc_state_extra = std::move(ss.mc_state_extra_);
|
||||
mc_state_extra_ = std::move(ss.mc_state_extra_);
|
||||
overload_history_ = ss.overload_history_;
|
||||
underload_history_ = ss.underload_history_;
|
||||
prev_state_utime_ = ss.utime_;
|
||||
|
@ -728,6 +734,7 @@ bool Collator::import_shard_state_data(block::ShardState& ss) {
|
|||
out_msg_queue_ = std::move(ss.out_msg_queue_);
|
||||
processed_upto_ = std::move(ss.processed_upto_);
|
||||
ihr_pending = std::move(ss.ihr_pending_);
|
||||
block_create_stats_ = std::move(ss.block_create_stats_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1250,6 +1257,8 @@ bool Collator::import_new_shard_top_blocks() {
|
|||
CHECK(ures.move_as_ok());
|
||||
store_shard_fees(std::move(prev_descr));
|
||||
store_shard_fees(std::move(descr));
|
||||
register_shard_block_creators(prev_bd->get_creator_list(prev_chain_len));
|
||||
register_shard_block_creators(sh_bd->get_creator_list(chain_len));
|
||||
used_shard_block_descr_.emplace_back(std::move(prev_bd));
|
||||
used_shard_block_descr_.emplace_back(sh_bd);
|
||||
tb_act += 2;
|
||||
|
@ -1284,6 +1293,7 @@ bool Collator::import_new_shard_top_blocks() {
|
|||
continue;
|
||||
}
|
||||
store_shard_fees(std::move(descr));
|
||||
register_shard_block_creators(sh_bd->get_creator_list(chain_len));
|
||||
shards_max_end_lt_ = std::max(shards_max_end_lt_, end_lt);
|
||||
LOG(INFO) << "updated top shard block information with " << sh_bd->block_id().to_str();
|
||||
CHECK(ures.move_as_ok());
|
||||
|
@ -1310,6 +1320,20 @@ bool Collator::import_new_shard_top_blocks() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Collator::register_shard_block_creators(std::vector<td::Bits256> creator_list) {
|
||||
for (const auto& x : creator_list) {
|
||||
LOG(DEBUG) << "registering block creator " << x.to_hex();
|
||||
if (!x.is_zero()) {
|
||||
auto res = block_create_count_.emplace(x, 1);
|
||||
if (!res.second) {
|
||||
(res.first->second)++;
|
||||
}
|
||||
block_create_total_++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collator::try_collate() {
|
||||
if (!preinit_complete) {
|
||||
LOG(DEBUG) << "running do_preinit()";
|
||||
|
@ -2912,34 +2936,34 @@ bool Collator::update_shard_config(const block::WorkchainSet& wc_set, const bloc
|
|||
WorkchainId wc_id{ton::workchainInvalid};
|
||||
Ref<block::WorkchainInfo> wc_info;
|
||||
ton::BlockSeqno& min_seqno = min_ref_mc_seqno_;
|
||||
return shard_conf_->process_sibling_shard_hashes([
|
||||
&wc_set, &wc_id, &wc_info, &ccvc, &min_seqno, now = now_, update_cc
|
||||
](block::McShardHash & cur, const block::McShardHash* sibling) {
|
||||
if (!cur.is_valid()) {
|
||||
return -2;
|
||||
}
|
||||
if (wc_id != cur.workchain()) {
|
||||
wc_id = cur.workchain();
|
||||
auto it = wc_set.find(wc_id);
|
||||
if (it == wc_set.end()) {
|
||||
wc_info.clear();
|
||||
} else {
|
||||
wc_info = it->second;
|
||||
}
|
||||
}
|
||||
min_seqno = std::min(min_seqno, cur.min_ref_mc_seqno_);
|
||||
return update_one_shard(cur, sibling, wc_info.get(), now, ccvc, update_cc);
|
||||
});
|
||||
return shard_conf_->process_sibling_shard_hashes(
|
||||
[&wc_set, &wc_id, &wc_info, &ccvc, &min_seqno, now = now_, update_cc](block::McShardHash& cur,
|
||||
const block::McShardHash* sibling) {
|
||||
if (!cur.is_valid()) {
|
||||
return -2;
|
||||
}
|
||||
if (wc_id != cur.workchain()) {
|
||||
wc_id = cur.workchain();
|
||||
auto it = wc_set.find(wc_id);
|
||||
if (it == wc_set.end()) {
|
||||
wc_info.clear();
|
||||
} else {
|
||||
wc_info = it->second;
|
||||
}
|
||||
}
|
||||
min_seqno = std::min(min_seqno, cur.min_ref_mc_seqno_);
|
||||
return update_one_shard(cur, sibling, wc_info.get(), now, ccvc, update_cc);
|
||||
});
|
||||
}
|
||||
|
||||
bool Collator::create_mc_state_extra() {
|
||||
if (!is_masterchain()) {
|
||||
CHECK(mc_state_extra.is_null());
|
||||
CHECK(mc_state_extra_.is_null());
|
||||
return true;
|
||||
}
|
||||
// should update mc_state_extra with a new McStateExtra
|
||||
block::gen::McStateExtra::Record state_extra;
|
||||
if (!tlb::unpack_cell(mc_state_extra, state_extra)) {
|
||||
if (!tlb::unpack_cell(mc_state_extra_, state_extra)) {
|
||||
return fatal_error("cannot unpack previous McStateExtra");
|
||||
}
|
||||
// 1. update config:ConfigParams
|
||||
|
@ -3003,7 +3027,7 @@ bool Collator::create_mc_state_extra() {
|
|||
return fatal_error("new ShardHashes is invalid");
|
||||
}
|
||||
// 4. check extension flags
|
||||
if (state_extra.r1.flags != 0) {
|
||||
if (state_extra.r1.flags & ~1) {
|
||||
return fatal_error(PSTRING() << "previous McStateExtra has unknown extension flags set (" << state_extra.r1.flags
|
||||
<< "), cannot handle these extensions");
|
||||
}
|
||||
|
@ -3052,13 +3076,14 @@ bool Collator::create_mc_state_extra() {
|
|||
CHECK(new_block_seqno > 0 && new_block_seqno == last_block_seqno + 1);
|
||||
vm::AugmentedDictionary dict{state_extra.r1.prev_blocks, 32, block::tlb::aug_OldMcBlocksInfo};
|
||||
vm::CellBuilder cb;
|
||||
LOG(DEBUG) << "previous state is a key state: " << config_->is_key_state();
|
||||
CHECK(cb.store_bool_bool(config_->is_key_state()) && store_prev_blk_ref(cb, false) &&
|
||||
dict.set_builder(td::BitArray<32>(last_block_seqno), cb, vm::Dictionary::SetMode::Add));
|
||||
state_extra.r1.prev_blocks = std::move(dict).extract_root();
|
||||
cb.reset();
|
||||
// 7. update after_key_block:Bool and last_key_block:(Maybe ExtBlkRef)
|
||||
state_extra.r1.after_key_block = is_key_block_;
|
||||
if (prev_key_block_seqno_) {
|
||||
if (prev_key_block_exists_) {
|
||||
// have non-trivial previous key block
|
||||
LOG(DEBUG) << "previous key block is " << prev_key_block_.to_str() << " lt " << prev_key_block_lt_;
|
||||
CHECK(cb.store_bool_bool(true) && store_ext_blk_ref_to(cb, prev_key_block_, prev_key_block_lt_));
|
||||
|
@ -3083,19 +3108,110 @@ bool Collator::create_mc_state_extra() {
|
|||
if (!global_balance_.pack_to(state_extra.global_balance)) {
|
||||
return fatal_error("cannot store global_balance");
|
||||
}
|
||||
// 9. pack new McStateExtra
|
||||
if (!tlb::pack(cb, state_extra) || !cb.finalize_to(mc_state_extra)) {
|
||||
// 9. update block creator stats
|
||||
if (!update_block_creator_stats()) {
|
||||
return fatal_error("cannot update BlockCreateStats in new masterchain state");
|
||||
}
|
||||
state_extra.r1.flags = (state_extra.r1.flags & ~1) | create_stats_enabled_;
|
||||
if (state_extra.r1.flags & 1) {
|
||||
vm::CellBuilder cb;
|
||||
// block_create_stats#17 counters:(HashmapE 256 CreatorStats) = BlockCreateStats;
|
||||
CHECK(cb.store_long_bool(0x17, 8) && cb.append_cellslice_bool(block_create_stats_->get_root()));
|
||||
auto cs = vm::load_cell_slice_ref(cb.finalize());
|
||||
state_extra.r1.block_create_stats = cs;
|
||||
if (verify >= 1) {
|
||||
if (!block::gen::t_BlockCreateStats.validate_csr(cs)) {
|
||||
cs->print_rec(std::cerr);
|
||||
block::gen::t_BlockCreateStats.print(std::cerr, *cs);
|
||||
return fatal_error("BlockCreateStats in the new masterchain state failed to pass automated validity checks");
|
||||
}
|
||||
}
|
||||
if (verbosity >= 4 * 1) {
|
||||
block::gen::t_BlockCreateStats.print(std::cerr, *cs);
|
||||
}
|
||||
} else {
|
||||
state_extra.r1.block_create_stats.clear();
|
||||
}
|
||||
// 10. pack new McStateExtra
|
||||
if (!tlb::pack(cb, state_extra) || !cb.finalize_to(mc_state_extra_)) {
|
||||
return fatal_error("cannot pack new McStateExtra");
|
||||
}
|
||||
if (verify >= 2) {
|
||||
LOG(INFO) << "verifying new McStateExtra";
|
||||
CHECK(block::gen::t_McStateExtra.validate_ref(mc_state_extra));
|
||||
CHECK(block::tlb::t_McStateExtra.validate_ref(mc_state_extra));
|
||||
CHECK(block::gen::t_McStateExtra.validate_ref(mc_state_extra_));
|
||||
CHECK(block::tlb::t_McStateExtra.validate_ref(mc_state_extra_));
|
||||
}
|
||||
LOG(INFO) << "McStateExtra created";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collator::update_block_creator_count(td::ConstBitPtr key, unsigned shard_incr, unsigned mc_incr) {
|
||||
LOG(DEBUG) << "increasing CreatorStats for " << key.to_hex(256) << " by (" << mc_incr << ", " << shard_incr << ")";
|
||||
block::DiscountedCounter mc_cnt, shard_cnt;
|
||||
auto cs = block_create_stats_->lookup(key, 256);
|
||||
if (!block::unpack_CreatorStats(std::move(cs), mc_cnt, shard_cnt)) {
|
||||
return fatal_error("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state");
|
||||
}
|
||||
// std::cerr << mc_cnt.to_str() << " " << shard_cnt.to_str() << std::endl;
|
||||
if (mc_incr && !mc_cnt.increase_by(mc_incr, now_)) {
|
||||
return fatal_error(PSTRING() << "cannot increase masterchain block counter in CreatorStats for " << key.to_hex(256)
|
||||
<< " by " << mc_incr << " (old value is " << mc_cnt.to_str() << ")");
|
||||
}
|
||||
if (shard_incr && !shard_cnt.increase_by(shard_incr, now_)) {
|
||||
return fatal_error(PSTRING() << "cannot increase shardchain block counter in CreatorStats for " << key.to_hex(256)
|
||||
<< " by " << shard_incr << " (old value is " << shard_cnt.to_str() << ")");
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
if (!block::store_CreatorStats(cb, mc_cnt, shard_cnt)) {
|
||||
return fatal_error("cannot serialize new CreatorStats for "s + key.to_hex(256));
|
||||
}
|
||||
if (!block_create_stats_->set_builder(key, 256, cb)) {
|
||||
return fatal_error("cannot store new CreatorStats for "s + key.to_hex(256) + " into dictionary");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Collator::creator_count_outdated(td::ConstBitPtr key, vm::CellSlice& cs) {
|
||||
block::DiscountedCounter mc_cnt, shard_cnt;
|
||||
if (!(block::fetch_CreatorStats(cs, mc_cnt, shard_cnt) && cs.empty_ext())) {
|
||||
return fatal_error("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state");
|
||||
}
|
||||
if (!(mc_cnt.increase_by(0, now_) && shard_cnt.increase_by(0, now_))) {
|
||||
return fatal_error("cannot amortize counters in CreatorStats for "s + key.to_hex(256));
|
||||
}
|
||||
if (!(mc_cnt.cnt65536 | shard_cnt.cnt65536)) {
|
||||
LOG(DEBUG) << "removing stale CreatorStats for " << key.to_hex(256);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Collator::update_block_creator_stats() {
|
||||
if (!create_stats_enabled_) {
|
||||
return true;
|
||||
}
|
||||
LOG(INFO) << "updating block creator statistics";
|
||||
CHECK(block_create_stats_);
|
||||
for (const auto& p : block_create_count_) {
|
||||
if (!update_block_creator_count(p.first.bits(), p.second, 0)) {
|
||||
return fatal_error("cannot update CreatorStats for "s + p.first.to_hex());
|
||||
}
|
||||
}
|
||||
if (/*!created_by_.is_zero() &&*/ !update_block_creator_count(created_by_.as_bits256().bits(), 0, 1)) {
|
||||
return fatal_error("cannot update CreatorStats for "s + created_by_.as_bits256().to_hex());
|
||||
}
|
||||
if (!update_block_creator_count(td::Bits256::zero().bits(), block_create_total_, 1)) {
|
||||
return fatal_error("cannot update CreatorStats with zero index (representing the sum of other CreatorStats)");
|
||||
}
|
||||
int cnt = block_create_stats_->filter([this](vm::CellSlice& cs, td::ConstBitPtr key, int key_len) {
|
||||
CHECK(key_len == 256);
|
||||
return creator_count_outdated(key, cs);
|
||||
});
|
||||
LOG(DEBUG) << "removed " << cnt << " stale CreatorStats entries";
|
||||
return cnt >= 0;
|
||||
}
|
||||
|
||||
td::Result<Ref<vm::Cell>> Collator::get_config_data_from_smc(const ton::StdSmcAddress& cfg_addr) {
|
||||
return block::get_config_data_from_smc(account_dict->lookup_ref(cfg_addr));
|
||||
}
|
||||
|
@ -3322,7 +3438,7 @@ bool Collator::create_shard_state() {
|
|||
&& cb2.store_bool_bool(!is_masterchain()) &&
|
||||
(is_masterchain() || store_master_ref(cb2)) // master_ref:(Maybe BlkMasterInfo)
|
||||
&& cb.store_ref_bool(cb2.finalize()) // ]
|
||||
&& cb.store_maybe_ref(mc_state_extra) // custom:(Maybe ^McStateExtra)
|
||||
&& cb.store_maybe_ref(mc_state_extra_) // custom:(Maybe ^McStateExtra)
|
||||
&& cb.finalize_to(state_root))) {
|
||||
return fatal_error("cannot create new ShardState");
|
||||
}
|
||||
|
@ -3500,10 +3616,10 @@ bool Collator::create_block_extra(Ref<vm::Cell>& block_extra) {
|
|||
return cb.store_long_bool(0x4a33f6fdU, 32) // block_extra
|
||||
&& in_msg_dict->append_dict_to_bool(cb2) && cb.store_ref_bool(cb2.finalize()) // in_msg_descr:^InMsgDescr
|
||||
&& out_msg_dict->append_dict_to_bool(cb2) && cb.store_ref_bool(cb2.finalize()) // out_msg_descr:^OutMsgDescr
|
||||
&& cb.store_ref_bool(shard_account_blocks_) // account_blocks:^ShardAccountBlocks
|
||||
&& cb.store_bits_bool(rand_seed_) // rand_seed:bits256
|
||||
&& cb.store_bits_bool(created_by) // created_by:bits256
|
||||
&& cb.store_bool_bool(mc) // custom:(Maybe
|
||||
&& cb.store_ref_bool(shard_account_blocks_) // account_blocks:^ShardAccountBlocks
|
||||
&& cb.store_bits_bool(rand_seed_) // rand_seed:bits256
|
||||
&& cb.store_bits_bool(created_by_.as_bits256()) // created_by:bits256
|
||||
&& cb.store_bool_bool(mc) // custom:(Maybe
|
||||
&& (!mc || (create_mc_block_extra(mc_block_extra) && cb.store_ref_bool(mc_block_extra))) // .. ^McBlockExtra)
|
||||
&& cb.finalize_to(block_extra); // = BlockExtra;
|
||||
}
|
||||
|
@ -3643,14 +3759,14 @@ bool Collator::create_block_candidate() {
|
|||
<< block_limit_status_->transactions;
|
||||
// 3. create a BlockCandidate
|
||||
block_candidate = std::make_unique<BlockCandidate>(
|
||||
Ed25519_PublicKey{created_by},
|
||||
created_by_,
|
||||
ton::BlockIdExt{ton::BlockId{shard, new_block_seqno}, new_block->get_hash().bits(),
|
||||
block::compute_file_hash(blk_slice.as_slice())},
|
||||
block::compute_file_hash(cdata_slice.as_slice()), blk_slice.clone(), cdata_slice.clone());
|
||||
// 4. save block candidate
|
||||
LOG(INFO) << "saving new BlockCandidate";
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::set_block_candidate, block_candidate->id,
|
||||
block_candidate->clone(), [self = get_self()](td::Result<td::Unit> saved)->void {
|
||||
block_candidate->clone(), [self = get_self()](td::Result<td::Unit> saved) -> void {
|
||||
LOG(DEBUG) << "got answer to set_block_candidate";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::return_block_candidate,
|
||||
std::move(saved));
|
||||
|
|
|
@ -180,7 +180,7 @@ void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_maste
|
|||
}
|
||||
|
||||
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, PublicKeyHash collator_id, td::Ref<ValidatorSet> validator_set,
|
||||
std::vector<BlockIdExt> prev, Ed25519_PublicKey collator_id, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
BlockSeqno seqno = 0;
|
||||
|
@ -190,8 +190,8 @@ void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& m
|
|||
}
|
||||
}
|
||||
td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, min_ts,
|
||||
min_masterchain_block_id, std::move(prev), std::move(validator_set),
|
||||
collator_id.bits256_value(), std::move(manager), timeout, std::move(promise))
|
||||
min_masterchain_block_id, std::move(prev), std::move(validator_set), collator_id,
|
||||
std::move(manager), timeout, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -41,14 +41,14 @@ ShardTopBlockDescrQ* ShardTopBlockDescrQ::make_copy() const {
|
|||
td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cell> proof_root, bool is_head) {
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error(-666, std::string{} + "link for block " + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() +
|
||||
return td::Status::Error(-666, "link for block "s + cur_id.to_str() + " inside ShardTopBlockDescr of " +
|
||||
block_id_.to_str() +
|
||||
" does not contain a valid Merkle proof for the block header");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != cur_id.root_hash) {
|
||||
return td::Status::Error(-666, std::string{} + "link for block " + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() +
|
||||
return td::Status::Error(-666, "link for block "s + cur_id.to_str() + " inside ShardTopBlockDescr of " +
|
||||
block_id_.to_str() +
|
||||
" contains a Merkle proof with incorrect root hash: expected " +
|
||||
cur_id.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
|
@ -56,18 +56,31 @@ td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cel
|
|||
BlockIdExt mc_blkid;
|
||||
auto res = block::unpack_block_prev_blk_try(virt_root, cur_id, link_prev_, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
return td::Status::Error(-666, std::string{"error in link for block "} + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() + ": " +
|
||||
res.move_as_error().to_string());
|
||||
return td::Status::Error(-666, "error in link for block "s + cur_id.to_str() + " inside ShardTopBlockDescr of " +
|
||||
block_id_.to_str() + ": " + res.move_as_error().to_string());
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::ValueFlow::Record flow;
|
||||
block::CurrencyCollection fees_collected, funds_created;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) && tlb::unpack_cell(blk.value_flow, flow) &&
|
||||
fees_collected.unpack(flow.fees_collected) && funds_created.unpack(flow.r2.created))) {
|
||||
return td::Status::Error(-666, std::string{"cannot unpack block header in link for block "} + cur_id.to_str());
|
||||
/*tlb::unpack_cell(blk.extra, extra) &&*/ fees_collected.unpack(flow.fees_collected) &&
|
||||
funds_created.unpack(flow.r2.created))) {
|
||||
return td::Status::Error(-666, "cannot unpack block header in link for block "s + cur_id.to_str());
|
||||
}
|
||||
// remove this "try ... catch ..." later and uncomment tlb::unpack_cell(blk.extra, extra) in the previous condition
|
||||
try {
|
||||
if (!tlb::unpack_cell(blk.extra, extra)) {
|
||||
return td::Status::Error(-666,
|
||||
"cannot unpack block extra header (BlockExtra) in link for block "s + cur_id.to_str());
|
||||
}
|
||||
} catch (vm::VmVirtError& err) {
|
||||
// backward compatibility with older Proofs / ProofLinks
|
||||
LOG(WARNING) << "virtualization error while parsing BlockExtra in proof link of " << cur_id.to_str()
|
||||
<< ", setting creator_id to zero: " << err.get_msg();
|
||||
extra.created_by.set_zero();
|
||||
}
|
||||
CHECK(after_split == info.after_split);
|
||||
if (info.gen_catchain_seqno != catchain_seqno_) {
|
||||
|
@ -113,6 +126,7 @@ td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cel
|
|||
chain_mc_blk_ids_.push_back(mc_blkid);
|
||||
chain_blk_ids_.push_back(cur_id);
|
||||
chain_fees_.emplace_back(std::move(fees_collected), std::move(funds_created));
|
||||
creators_.push_back(extra.created_by);
|
||||
if (!is_head) {
|
||||
if (info.after_split || info.after_merge) {
|
||||
return td::Status::Error(
|
||||
|
@ -491,6 +505,17 @@ Ref<block::McShardHash> ShardTopBlockDescrQ::get_prev_descr(int pos, int sum_cnt
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<td::Bits256> ShardTopBlockDescrQ::get_creator_list(int count) const {
|
||||
if (!is_valid() || count < 0 || (unsigned)count > size()) {
|
||||
return {};
|
||||
}
|
||||
std::vector<td::Bits256> res;
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
res.push_back(creators_.at(i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescr::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(descr_));
|
||||
|
|
|
@ -85,6 +85,7 @@ class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase {
|
|||
Ref<block::McShardHash> get_top_descr(int sum_cnt = 0) const {
|
||||
return get_prev_descr(0, sum_cnt);
|
||||
}
|
||||
std::vector<td::Bits256> get_creator_list(int count) const;
|
||||
Ref<vm::Cell> get_root() const {
|
||||
return root_;
|
||||
}
|
||||
|
@ -131,6 +132,7 @@ class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase {
|
|||
std::vector<BlockIdExt> chain_mc_blk_ids_;
|
||||
std::vector<BlockIdExt> link_prev_;
|
||||
std::vector<std::pair<block::CurrencyCollection, block::CurrencyCollection>> chain_fees_;
|
||||
std::vector<td::Bits256> creators_;
|
||||
UnixTime first_gen_utime_;
|
||||
|
||||
ShardTopBlockDescrQ(const ShardTopBlockDescrQ& other) = default;
|
||||
|
|
|
@ -152,6 +152,12 @@ void ValidateQuery::start_up() {
|
|||
alarm_timestamp() = timeout;
|
||||
rand_seed_.set_zero();
|
||||
|
||||
created_by_ = block_candidate.pubkey;
|
||||
if (created_by_.is_zero()) {
|
||||
// !!FIXME!! remove this debug later
|
||||
td::as<td::uint32>(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
|
||||
}
|
||||
|
||||
CHECK(id_ == block_candidate.id);
|
||||
if (ShardIdFull(id_) != shard_) {
|
||||
soft_reject_query(PSTRING() << "block candidate belongs to shard " << ShardIdFull(id_).to_str()
|
||||
|
@ -431,6 +437,10 @@ bool ValidateQuery::init_parse() {
|
|||
return reject_query("after_merge value mismatch in block header");
|
||||
}
|
||||
rand_seed_ = extra.rand_seed;
|
||||
if (created_by_ != extra.created_by) {
|
||||
return reject_query("block candidate "s + id_.to_str() + " has creator " + created_by_.to_hex() +
|
||||
" but the block header contains different value " + extra.created_by.to_hex());
|
||||
}
|
||||
if (is_masterchain()) {
|
||||
if (!extra.custom->size_refs()) {
|
||||
return reject_query("masterchain block candidate without McBlockExtra");
|
||||
|
@ -658,6 +668,7 @@ bool ValidateQuery::try_unpack_mc_state() {
|
|||
mc_state_root_,
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needLibraries | block::ConfigInfo::needValidatorSet |
|
||||
block::ConfigInfo::needWorkchainInfo | block::ConfigInfo::needStateExtraRoot |
|
||||
block::ConfigInfo::needCapabilities |
|
||||
(is_masterchain() ? block::ConfigInfo::needAccountsRoot | block::ConfigInfo::needSpecialSmc : 0));
|
||||
if (res.is_error()) {
|
||||
return fatal_error(-666, "cannot extract configuration from reference masterchain state "s + mc_blkid_.to_str() +
|
||||
|
@ -666,6 +677,8 @@ bool ValidateQuery::try_unpack_mc_state() {
|
|||
config_ = res.move_as_ok();
|
||||
CHECK(config_);
|
||||
config_->set_block_id_ext(mc_blkid_);
|
||||
ihr_enabled_ = config_->ihr_enabled();
|
||||
create_stats_enabled_ = config_->create_stats_enabled();
|
||||
old_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
if (!is_masterchain()) {
|
||||
new_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
|
@ -677,7 +690,8 @@ bool ValidateQuery::try_unpack_mc_state() {
|
|||
if (global_id_ != config_->get_global_blockchain_id()) {
|
||||
return reject_query("blockchain global id mismatch");
|
||||
}
|
||||
if (config_->get_last_key_block(prev_key_block_, prev_key_block_lt_)) {
|
||||
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
|
||||
if (prev_key_block_exists_) {
|
||||
prev_key_block_seqno_ = prev_key_block_.seqno();
|
||||
} else {
|
||||
prev_key_block_seqno_ = 0;
|
||||
|
@ -1044,7 +1058,7 @@ bool ValidateQuery::compute_next_state() {
|
|||
state_root_, block::ConfigInfo::needShardHashes | block::ConfigInfo::needLibraries |
|
||||
block::ConfigInfo::needValidatorSet | block::ConfigInfo::needWorkchainInfo |
|
||||
block::ConfigInfo::needStateExtraRoot | block::ConfigInfo::needAccountsRoot |
|
||||
block::ConfigInfo::needSpecialSmc);
|
||||
block::ConfigInfo::needSpecialSmc | block::ConfigInfo::needCapabilities);
|
||||
if (r_config_info.is_error()) {
|
||||
return reject_query("cannot extract configuration from new masterchain state "s + mc_blkid_.to_str() + " : " +
|
||||
r_config_info.error().to_string());
|
||||
|
@ -1508,6 +1522,8 @@ bool ValidateQuery::check_one_shard(const block::McShardHash& info, const block:
|
|||
descr->funds_created_.to_str());
|
||||
}
|
||||
}
|
||||
// register shard block creators
|
||||
register_shard_block_creators(sh_bd->get_creator_list(chain_len));
|
||||
// ...
|
||||
} catch (vm::VmError& err) {
|
||||
return reject_query("incorrect ShardTopBlockDescr for "s + shard.to_str() +
|
||||
|
@ -1677,6 +1693,21 @@ bool ValidateQuery::check_shard_layout() {
|
|||
return check_mc_validator_info(is_key_block_ || (now_ / ccvc.mc_cc_lifetime > prev_now_ / ccvc.mc_cc_lifetime));
|
||||
}
|
||||
|
||||
// similar to Collator::register_shard_block_creators
|
||||
bool ValidateQuery::register_shard_block_creators(std::vector<td::Bits256> creator_list) {
|
||||
for (const auto& x : creator_list) {
|
||||
LOG(DEBUG) << "registering block creator " << x.to_hex();
|
||||
if (!x.is_zero()) {
|
||||
auto res = block_create_count_.emplace(x, 1);
|
||||
if (!res.second) {
|
||||
(res.first->second)++;
|
||||
}
|
||||
block_create_total_++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateQuery::check_cur_validator_set() {
|
||||
CatchainSeqno cc_seqno = 0;
|
||||
auto nodes = config_->compute_validator_set_cc(shard_, now_, &cc_seqno);
|
||||
|
@ -4949,9 +4980,15 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
return reject_query("invalid configuration update");
|
||||
}
|
||||
// ...
|
||||
// flags:(## 16) { flags = 0 }
|
||||
if (new_extra.r1.flags != 0) {
|
||||
return reject_query("new McStateExtra has non-zero (unsupported) extension flags; validator too old?");
|
||||
// flags:(## 16) { flags <= 1 }
|
||||
if (new_extra.r1.flags & ~1) {
|
||||
return reject_query(PSTRING() << "new McStateExtra has non-zero (unsupported) extension flags "
|
||||
<< new_extra.r1.flags << "; validator too old?");
|
||||
}
|
||||
if ((bool)(new_extra.r1.flags & 1) != create_stats_enabled_) {
|
||||
return reject_query(PSTRING() << "new McStateExtra has extension flags " << new_extra.r1.flags
|
||||
<< " but active configuration defines create_stats_enabled="
|
||||
<< create_stats_enabled_);
|
||||
}
|
||||
// validator_info:ValidatorInfo
|
||||
// (already checked in check_mc_validator_info())
|
||||
|
@ -5043,11 +5080,21 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
return reject_query("new masterchain state declares previous key block to be "s + blkid.to_str() +
|
||||
" but the value computed from previous masterchain state is " + prev_key_block_.to_str());
|
||||
}
|
||||
} else if (prev_key_block_seqno_ > 0) {
|
||||
} else if (prev_key_block_exists_) {
|
||||
return reject_query(PSTRING() << "new masterchain state declares no previous key block, but the block header "
|
||||
"announces previous key block seqno "
|
||||
<< prev_key_block_seqno_);
|
||||
}
|
||||
// block_create_stats:(flags . 0)?BlockCreateStats
|
||||
if (new_extra.r1.flags & 1) {
|
||||
block::gen::BlockCreateStats::Record rec;
|
||||
if (!tlb::csr_unpack(new_extra.r1.block_create_stats, rec)) {
|
||||
return reject_query("cannot unpack BlockCreateStats in the new masterchain state");
|
||||
}
|
||||
if (!check_block_create_stats()) {
|
||||
return reject_query("invalid BlockCreateStats update in the new masterchain state");
|
||||
}
|
||||
}
|
||||
// global_balance:CurrencyCollection
|
||||
block::CurrencyCollection global_balance, old_global_balance;
|
||||
if (!global_balance.validate_unpack(new_extra.global_balance)) {
|
||||
|
@ -5069,6 +5116,136 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
return true;
|
||||
}
|
||||
|
||||
td::Status ValidateQuery::check_counter_update(const block::DiscountedCounter& oc, const block::DiscountedCounter& nc,
|
||||
unsigned expected_incr) {
|
||||
block::DiscountedCounter cc{oc};
|
||||
if (nc.is_zero()) {
|
||||
if (expected_incr) {
|
||||
return td::Status::Error(PSTRING() << "new counter total is zero, but the total should have been increased by "
|
||||
<< expected_incr);
|
||||
}
|
||||
if (oc.is_zero()) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
cc.increase_by(0, now_);
|
||||
if (!cc.almost_zero()) {
|
||||
return td::Status::Error(
|
||||
"counter has been reset to zero, but it still has non-zero components after relaxation: "s + cc.to_str() +
|
||||
"; original value before relaxation was " + oc.to_str());
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
if (!expected_incr) {
|
||||
if (oc == nc) {
|
||||
return td::Status::OK();
|
||||
} else {
|
||||
return td::Status::Error("unnecessary relaxation of counter from "s + oc.to_str() + " to " + nc.to_str() +
|
||||
" without an increment");
|
||||
}
|
||||
}
|
||||
if (nc.total < oc.total) {
|
||||
return td::Status::Error(PSTRING() << "total counter goes back from " << oc.total << " to " << nc.total
|
||||
<< " (increment by " << expected_incr << " expected instead)");
|
||||
}
|
||||
if (nc.total != oc.total + expected_incr) {
|
||||
return td::Status::Error(PSTRING() << "total counter has been incremented by " << nc.total - oc.total << ", from "
|
||||
<< oc.total << " to " << nc.total << " (increment by " << expected_incr
|
||||
<< " expected instead)");
|
||||
}
|
||||
if (!cc.increase_by(expected_incr, now_)) {
|
||||
return td::Status::Error(PSTRING() << "old counter value " << oc.to_str() << " cannot be increased by "
|
||||
<< expected_incr);
|
||||
}
|
||||
if (!cc.almost_equals(nc)) {
|
||||
return td::Status::Error(PSTRING() << "counter " << oc.to_str() << " has been increased by " << expected_incr
|
||||
<< " with an incorrect resulting value " << nc.to_str()
|
||||
<< "; correct result should be " << cc.to_str()
|
||||
<< " (up to +/-1 in the last two components)");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
bool ValidateQuery::check_one_block_creator_update(td::ConstBitPtr key, Ref<vm::CellSlice> old_val,
|
||||
Ref<vm::CellSlice> new_val) {
|
||||
LOG(DEBUG) << "checking update of CreatorStats for "s + key.to_hex(256);
|
||||
block::DiscountedCounter mc0, shard0, mc1, shard1;
|
||||
if (!block::unpack_CreatorStats(std::move(old_val), mc0, shard0)) {
|
||||
return reject_query("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state");
|
||||
}
|
||||
bool nv_exists = new_val.not_null();
|
||||
if (!block::unpack_CreatorStats(std::move(new_val), mc1, shard1)) {
|
||||
return reject_query("cannot unpack CreatorStats for "s + key.to_hex(256) + " from new masterchain state");
|
||||
}
|
||||
unsigned mc_incr = (created_by_ == key);
|
||||
unsigned shard_incr = 0;
|
||||
if (key.is_zero(256)) {
|
||||
mc_incr = 1;
|
||||
shard_incr = block_create_total_;
|
||||
} else {
|
||||
auto it = block_create_count_.find(td::Bits256{key});
|
||||
shard_incr = (it == block_create_count_.end() ? 0 : it->second);
|
||||
}
|
||||
auto err = check_counter_update(mc0, mc1, mc_incr);
|
||||
if (err.is_error()) {
|
||||
return reject_query("invalid update of created masterchain blocks counter in CreatorStats for "s + key.to_hex(256) +
|
||||
" : " + err.to_string());
|
||||
}
|
||||
err = check_counter_update(shard0, shard1, shard_incr);
|
||||
if (err.is_error()) {
|
||||
return reject_query("invalid update of created shardchain blocks counter in CreatorStats for "s + key.to_hex(256) +
|
||||
" : " + err.to_string());
|
||||
}
|
||||
if (mc1.is_zero() && shard1.is_zero() && nv_exists) {
|
||||
return reject_query("new CreatorStats for "s + key.to_hex(256) +
|
||||
" contains two zero counters (it should have been completely deleted instead)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// similar to Collator::update_block_creator_stats()
|
||||
bool ValidateQuery::check_block_create_stats() {
|
||||
LOG(INFO) << "checking all CreatorStats updates between the old and the new state";
|
||||
try {
|
||||
CHECK(ps_.block_create_stats_ && ns_.block_create_stats_);
|
||||
if (!ps_.block_create_stats_->scan_diff(
|
||||
*ns_.block_create_stats_,
|
||||
[this](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> old_val, Ref<vm::CellSlice> new_val) {
|
||||
CHECK(key_len == 256);
|
||||
return check_one_block_creator_update(key, std::move(old_val), std::move(new_val));
|
||||
},
|
||||
3 /* check augmentation of changed nodes */)) {
|
||||
return reject_query("invalid BlockCreateStats dictionary in the new state");
|
||||
}
|
||||
for (const auto& p : block_create_count_) {
|
||||
auto old_val = ps_.block_create_stats_->lookup(p.first);
|
||||
auto new_val = ns_.block_create_stats_->lookup(p.first);
|
||||
if (old_val.is_null() != new_val.is_null()) {
|
||||
continue;
|
||||
}
|
||||
if (old_val.not_null() && !new_val->contents_equal(*old_val)) {
|
||||
continue;
|
||||
}
|
||||
if (!check_one_block_creator_update(p.first.bits(), std::move(old_val), std::move(new_val))) {
|
||||
return reject_query("invalid update of BlockCreator entry for "s + p.first.to_hex());
|
||||
}
|
||||
}
|
||||
auto key = td::Bits256::zero();
|
||||
auto old_val = ps_.block_create_stats_->lookup(key);
|
||||
auto new_val = ns_.block_create_stats_->lookup(key);
|
||||
if (new_val.is_null()) {
|
||||
return reject_query(
|
||||
"new masterchain state does not contain a BlockCreator entry with zero key with total statistics");
|
||||
}
|
||||
if (!check_one_block_creator_update(key.bits(), std::move(old_val), std::move(new_val))) {
|
||||
return reject_query("invalid update of BlockCreator entry for "s + key.to_hex());
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return reject_query("invalid BlockCreateStats dictionary difference between the old and the new state: "s +
|
||||
err.get_msg());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateQuery::check_one_shard_fee(ShardIdFull shard, const block::CurrencyCollection& fees,
|
||||
const block::CurrencyCollection& created) {
|
||||
auto descr = new_shard_conf_->get_shard_hash(shard);
|
||||
|
|
|
@ -135,10 +135,12 @@ class ValidateQuery : public td::actor::Actor {
|
|||
bool is_key_block_{false};
|
||||
bool update_shard_cc_{false};
|
||||
bool is_fake_{false};
|
||||
bool prev_key_block_exists_{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_;
|
||||
Ref<vm::Cell> state_root_;
|
||||
|
@ -174,6 +176,8 @@ class ValidateQuery : public td::actor::Actor {
|
|||
ton::LogicalTime max_shard_lt_{0};
|
||||
|
||||
int global_id_{0};
|
||||
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_;
|
||||
|
@ -197,6 +201,9 @@ class ValidateQuery : public td::actor::Actor {
|
|||
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_;
|
||||
|
@ -285,6 +292,7 @@ class ValidateQuery : public td::actor::Actor {
|
|||
bool check_one_shard(const block::McShardHash& info, const block::McShardHash* sibling,
|
||||
const block::WorkchainInfo* wc_info, const block::CatchainValidatorsConfig& ccvc);
|
||||
bool check_shard_layout();
|
||||
bool register_shard_block_creators(std::vector<td::Bits256> creator_list);
|
||||
bool check_cur_validator_set();
|
||||
bool check_mc_validator_info(bool update_mc_cc);
|
||||
bool check_utime_lt();
|
||||
|
@ -342,6 +350,10 @@ class ValidateQuery : public td::actor::Actor {
|
|||
bool check_one_prev_dict_update(ton::BlockSeqno seqno, Ref<vm::CellSlice> old_val_extra,
|
||||
Ref<vm::CellSlice> new_val_extra);
|
||||
bool check_mc_state_extra();
|
||||
td::Status check_counter_update(const block::DiscountedCounter& oc, const block::DiscountedCounter& nc,
|
||||
unsigned expected_incr);
|
||||
bool check_one_block_creator_update(td::ConstBitPtr key, Ref<vm::CellSlice> old_val, Ref<vm::CellSlice> new_val);
|
||||
bool check_block_create_stats();
|
||||
bool check_one_shard_fee(ShardIdFull shard, const block::CurrencyCollection& fees,
|
||||
const block::CurrencyCollection& create);
|
||||
bool check_mc_block_extra();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue