diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index 0f019b068..554a70d9e 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -516,34 +516,50 @@ td::Result<std::unique_ptr<ValidatorSet>> Config::unpack_validator_set(Ref<vm::C "maximal index in a validator set dictionary must be one less than the total number of validators"); } auto ptr = std::make_unique<ValidatorSet>(rec.utime_since, rec.utime_until, rec.total, rec.main); - for (int i = 0; i < rec.total; i++) { - key_buffer.store_ulong(i); - auto descr_cs = dict.lookup(key_buffer.bits(), 16); - if (descr_cs.is_null()) { - return td::Status::Error("indices in a validator set dictionary must be integers 0..total-1"); - } + + std::vector<bool> seen_keys(rec.total); + td::Status error; + + auto validator_set_check_fn = [&](Ref<vm::CellSlice> descr_cs, td::ConstBitPtr key, int n) -> bool { + int i = static_cast<int>(key.get_int(n)); + CHECK(i >= 0 && i < rec.total && !seen_keys[i]); + seen_keys[i] = true; + gen::ValidatorDescr::Record_validator_addr descr; if (!tlb::csr_unpack(descr_cs, descr)) { descr.adnl_addr.set_zero(); if (!(gen::t_ValidatorDescr.unpack_validator(descr_cs.write(), descr.public_key, descr.weight) && descr_cs->empty_ext())) { - return td::Status::Error(PSLICE() << "validator #" << i - << " has an invalid ValidatorDescr record in the validator set dictionary"); + error = td::Status::Error(PSLICE() << "validator #" << i + << " has an invalid ValidatorDescr record in the validator set dictionary"); + return false; } } gen::SigPubKey::Record sig_pubkey; if (!tlb::csr_unpack(std::move(descr.public_key), sig_pubkey)) { - return td::Status::Error(PSLICE() << "validator #" << i - << " has no public key or its public key is in unsupported format"); + error = td::Status::Error(PSLICE() << "validator #" << i + << " has no public key or its public key is in unsupported format"); + return false; } if (!descr.weight) { - return td::Status::Error(PSLICE() << "validator #" << i << " has zero weight"); + error = td::Status::Error(PSLICE() << "validator #" << i << " has zero weight"); + return false; } if (descr.weight > ~(ptr->total_weight)) { - return td::Status::Error("total weight of all validators in validator set exceeds 2^64"); + error = td::Status::Error("total weight of all validators in validator set exceeds 2^64"); + return false; } ptr->list.emplace_back(sig_pubkey.pubkey, descr.weight, ptr->total_weight, descr.adnl_addr); ptr->total_weight += descr.weight; + return true; + }; + + if (!dict.check_for_each(validator_set_check_fn)) { + CHECK(error.is_error()); + return error; + } + if (std::find(seen_keys.begin(), seen_keys.end(), false) != seen_keys.end()) { + return td::Status::Error("indices in a validator set dictionary must be integers 0..total-1"); } if (rec.total_weight && rec.total_weight != ptr->total_weight) { return td::Status::Error("validator set declares incorrect total weight");