diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0236b01e31..aadaf22d21 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -89,8 +89,8 @@ jobs: options: - name: "Self-hosted: Linux: gcc-12 ASAN" run: ./housekeeping/make_build.sh -DCLEAR_OBJS=ON -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/gcc-12_cxx20.cmake -DASAN=ON - - name: "Self-hosted: Linux: gcc-12 TSAN WAVM" - run: ./housekeeping/make_build.sh -DCLEAR_OBJS=ON -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/gcc-12_cxx20.cmake -DTSAN=ON -DWASM_COMPILER=WAVM + - name: "Self-hosted: Linux: clang-16 TSAN WAVM" + run: ./housekeeping/make_build.sh -DCLEAR_OBJS=ON -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/clang-16_cxx20.cmake -DTSAN=ON -DWASM_COMPILER=WAVM - name: "Self-hosted: Linux: clang-16 UBSAN" run: ./housekeeping/make_build.sh -DCLEAR_OBJS=ON -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/clang-16_cxx20.cmake -DUBSAN=ON - name: "Self-hosted: Linux: clang-16 External Project" @@ -342,4 +342,4 @@ jobs: - uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 - name: Run test working-directory: ./zombienet/docker - run: make ${{ matrix.options.test }} ZOMBIE_TESTER_IMAGE=zombie-tester:latest \ No newline at end of file + run: make ${{ matrix.options.test }} ZOMBIE_TESTER_IMAGE=zombie-tester:latest diff --git a/core/consensus/babe/impl/babe.cpp b/core/consensus/babe/impl/babe.cpp index 2aee16bc5a..b15c4ce6f7 100644 --- a/core/consensus/babe/impl/babe.cpp +++ b/core/consensus/babe/impl/babe.cpp @@ -34,7 +34,6 @@ #include "offchain/offchain_worker_factory.hpp" #include "offchain/offchain_worker_pool.hpp" #include "parachain/availability/bitfield/store.hpp" -#include "parachain/backing/store.hpp" #include "parachain/parachain_inherent_data.hpp" #include "parachain/validator/parachain_processor.hpp" #include "primitives/inherent_data.hpp" @@ -170,10 +169,27 @@ namespace kagome::consensus::babe { } const auto &authorities = config.value()->authorities; - if (session_keys_->getBabeKeyPair(authorities)) { + const auto &kp_opt = session_keys_->getBabeKeyPair(authorities); + if (kp_opt.has_value()) { + const auto &authority_index = kp_opt->second; + + auto disabled_validators_res = babe_api_->disabled_validators(block.hash); + if (disabled_validators_res.has_error()) { + SL_CRITICAL( + log_, "Can't obtain disabled validators list for block {}", block); + } + const auto &disabled_validators = disabled_validators_res.value(); + + if (std::binary_search(disabled_validators.begin(), + disabled_validators.end(), + authority_index)) { + return ValidatorStatus::DisabledValidator; + } + if (authorities.size() > 1) { return ValidatorStatus::Validator; } + return ValidatorStatus::SingleValidator; } @@ -205,20 +221,23 @@ namespace kagome::consensus::babe { if (lottery_->getEpoch() != epoch) { is_active_validator_ = changeEpoch(epoch, best_block); metric_is_relaychain_validator_->set(is_active_validator_); - if (not is_active_validator_) { - if (is_validator_by_config_) { - SL_VERBOSE(log_, - "Authority not known, skipping slot processing. " - "Probably authority list has changed."); - } + if (not is_active_validator_ and is_validator_by_config_) { + SL_VERBOSE(log_, + "Authority not known, skipping slot processing. " + "Probably authority list has changed."); } else { - SL_VERBOSE(log_, "Node is active validator in epoch {}", epoch); + SL_VERBOSE(log_, "Node is validator in epoch {}", epoch); } } if (not is_active_validator_) { SL_TRACE(log_, "Node is not active validator in epoch {}", epoch); - return SlotLeadershipError::NO_VALIDATOR; + return SlotLeadershipError::NON_VALIDATOR; + } + + auto validator_status = getValidatorStatus(best_block, epoch); + if (validator_status == ValidatorStatus::DisabledValidator) { + return SlotLeadershipError::DISABLED_VALIDATOR; } if (not checkSlotLeadership(best_block, slot)) { diff --git a/core/consensus/babe/impl/babe_block_validator_impl.cpp b/core/consensus/babe/impl/babe_block_validator_impl.cpp index 851941384b..465d86122e 100644 --- a/core/consensus/babe/impl/babe_block_validator_impl.cpp +++ b/core/consensus/babe/impl/babe_block_validator_impl.cpp @@ -8,6 +8,7 @@ #include +#include "application/app_state_manager.hpp" #include "consensus/babe/babe_config_repository.hpp" #include "consensus/babe/babe_lottery.hpp" #include "consensus/babe/impl/babe_digests_util.hpp" @@ -20,8 +21,8 @@ #include "prepare_transcript.hpp" #include "primitives/inherent_data.hpp" #include "primitives/transcript.hpp" +#include "runtime/runtime_api/babe_api.hpp" #include "runtime/runtime_api/offchain_worker_api.hpp" -#include "storage/trie/serialization/ordered_trie_hash.hpp" #include "threshold_util.hpp" OUTCOME_CPP_DEFINE_CATEGORY(kagome::consensus::babe, @@ -29,8 +30,10 @@ OUTCOME_CPP_DEFINE_CATEGORY(kagome::consensus::babe, e) { using E = kagome::consensus::babe::BabeBlockValidatorImpl::ValidationError; switch (e) { - case E::NO_AUTHORITIES: - return "no authorities are provided for the validation"; + case E::NO_VALIDATOR: + return "author of block is not active validator"; + case E::DISABLED_VALIDATOR: + return "author of block is disabled validator"; case E::INVALID_SIGNATURE: return "SR25519 signature, which is in BABE header, is invalid"; case E::INVALID_VRF: @@ -46,21 +49,51 @@ OUTCOME_CPP_DEFINE_CATEGORY(kagome::consensus::babe, namespace kagome::consensus::babe { BabeBlockValidatorImpl::BabeBlockValidatorImpl( + std::shared_ptr app_state_manager, LazySPtr slots_util, std::shared_ptr config_repo, std::shared_ptr hasher, std::shared_ptr sr25519_provider, - std::shared_ptr vrf_provider) + std::shared_ptr vrf_provider, + std::shared_ptr babe_api, + primitives::events::SyncStateSubscriptionEnginePtr sync_state_observable) : log_(log::createLogger("BabeBlockValidatorImpl", "babe")), slots_util_(std::move(slots_util)), config_repo_(std::move(config_repo)), hasher_(std::move(hasher)), sr25519_provider_(std::move(sr25519_provider)), - vrf_provider_(std::move(vrf_provider)) { + vrf_provider_(std::move(vrf_provider)), + babe_api_(std::move(babe_api)), + sync_state_observable_(std::move(sync_state_observable)) { BOOST_ASSERT(config_repo_); BOOST_ASSERT(hasher_); BOOST_ASSERT(sr25519_provider_); BOOST_ASSERT(vrf_provider_); + BOOST_ASSERT(babe_api_); + BOOST_ASSERT(sync_state_observable_); + + app_state_manager->takeControl(*this); + } + + void BabeBlockValidatorImpl::prepare() { + sync_state_observer_ = + std::make_shared( + sync_state_observable_, false); + sync_state_observer_->subscribe( + sync_state_observer_->generateSubscriptionSetId(), + primitives::events::SyncStateEventType::kSyncState); + sync_state_observer_->setCallback( + [wp{weak_from_this()}]( + auto /*set_id*/, + bool &synchronized, + auto /*event_type*/, + const primitives::events::SyncStateEventParams &event) mutable { + if (auto self = wp.lock()) { + if (event == consensus::SyncState::SYNCHRONIZED) { + self->was_synchronized_ = true; + } + } + }); } outcome::result BabeBlockValidatorImpl::validateHeader( @@ -94,6 +127,13 @@ namespace kagome::consensus::babe { epoch_number, config.randomness); + if (babe_header.authority_index >= config.authorities.size()) { + SL_VERBOSE(log_, + "Block {} is invalid because validator index out of bound", + block_header.blockInfo()); + return ValidationError::NO_VALIDATOR; + } + auto threshold = calculateThreshold(config.leadership_rate, config.authorities, babe_header.authority_index); @@ -105,6 +145,27 @@ namespace kagome::consensus::babe { threshold, config)); + // If we were synchronized, + // we have available runtime to check disabled validators + if (was_synchronized_) { + std::vector disabled_validators; + if (auto res = babe_api_->disabled_validators(block_header.parent_hash); + res.has_error()) { + SL_CRITICAL(log_, + "Can't obtain disabled validators list for block {}", + block_header.blockInfo()); + } + + if (std::binary_search(disabled_validators.begin(), + disabled_validators.end(), + babe_header.authority_index)) { + SL_VERBOSE(log_, + "Block {} is invalid because produced by disabled validator", + block_header.blockInfo()); + return ValidationError::DISABLED_VALIDATOR; + } + } + return outcome::success(); } diff --git a/core/consensus/babe/impl/babe_block_validator_impl.hpp b/core/consensus/babe/impl/babe_block_validator_impl.hpp index 24c44f4f0a..2218e2bdec 100644 --- a/core/consensus/babe/impl/babe_block_validator_impl.hpp +++ b/core/consensus/babe/impl/babe_block_validator_impl.hpp @@ -18,6 +18,10 @@ #include "primitives/event_types.hpp" #include "telemetry/service.hpp" +namespace kagome::application { + class AppStateManager; +} + namespace kagome::consensus { class SlotsUtil; } @@ -33,6 +37,10 @@ namespace kagome::crypto { class VRFProvider; } // namespace kagome::crypto +namespace kagome::runtime { + class BabeApi; +} + namespace kagome::consensus::babe { class BabeBlockValidatorImpl @@ -40,17 +48,24 @@ namespace kagome::consensus::babe { public std::enable_shared_from_this { public: BabeBlockValidatorImpl( + std::shared_ptr app_state_manager, LazySPtr slots_util, std::shared_ptr config_repo, std::shared_ptr hasher, std::shared_ptr sr25519_provider, - std::shared_ptr vrf_provider); + std::shared_ptr vrf_provider, + std::shared_ptr babe_api, + primitives::events::SyncStateSubscriptionEnginePtr + sync_state_observable); + + void prepare(); outcome::result validateHeader( const primitives::BlockHeader &block_header) const; enum class ValidationError { - NO_AUTHORITIES = 1, + NO_VALIDATOR = 1, + DISABLED_VALIDATOR, INVALID_SIGNATURE, INVALID_VRF, TWO_BLOCKS_IN_SLOT, @@ -107,6 +122,11 @@ namespace kagome::consensus::babe { std::shared_ptr hasher_; std::shared_ptr sr25519_provider_; std::shared_ptr vrf_provider_; + std::shared_ptr babe_api_; + primitives::events::SyncStateSubscriptionEnginePtr sync_state_observable_; + + bool was_synchronized_ = false; + primitives::events::SyncStateEventSubscriberPtr sync_state_observer_; }; } // namespace kagome::consensus::babe diff --git a/core/consensus/babe/impl/babe_config_repository_impl.cpp b/core/consensus/babe/impl/babe_config_repository_impl.cpp index 8d35475133..3764315dac 100644 --- a/core/consensus/babe/impl/babe_config_repository_impl.cpp +++ b/core/consensus/babe/impl/babe_config_repository_impl.cpp @@ -132,7 +132,6 @@ namespace kagome::consensus::babe { [[maybe_unused]] bool active_ = false; - // TODO(xDimon): Perhaps, should be observed by all non-finalized blocks auto best = block_tree_->bestBlock(); auto consensus = consensus_selector_.get()->getProductionConsensus(best); if (std::dynamic_pointer_cast(consensus)) { diff --git a/core/consensus/babe/impl/threshold_util.cpp b/core/consensus/babe/impl/threshold_util.cpp index 4e6b8b7cda..f0c334793d 100644 --- a/core/consensus/babe/impl/threshold_util.cpp +++ b/core/consensus/babe/impl/threshold_util.cpp @@ -14,6 +14,8 @@ namespace kagome::consensus::babe { Threshold calculateThreshold(const std::pair &ratio, const Authorities &authorities, AuthorityIndex authority_index) { + BOOST_ASSERT(authority_index < authorities.size()); + double float_point_ratio = double(ratio.first) / ratio.second; using boost::adaptors::transformed; diff --git a/core/consensus/babe/types/authority.hpp b/core/consensus/babe/types/authority.hpp index f2d3aff88d..7911806008 100644 --- a/core/consensus/babe/types/authority.hpp +++ b/core/consensus/babe/types/authority.hpp @@ -24,6 +24,4 @@ namespace kagome::consensus::babe { using Authorities = common::SLVector; - using AuthorityIndex = uint32_t; - } // namespace kagome::consensus::babe diff --git a/core/consensus/grandpa/types/authority.hpp b/core/consensus/grandpa/types/authority.hpp index 8bd69a87a2..f8b83c387c 100644 --- a/core/consensus/grandpa/types/authority.hpp +++ b/core/consensus/grandpa/types/authority.hpp @@ -25,8 +25,6 @@ namespace kagome::consensus::grandpa { using Authorities = common::SLVector; - using AuthorityIndex = uint32_t; - using AuthoritySetId = uint64_t; /* diff --git a/core/consensus/grandpa/voter_set.hpp b/core/consensus/grandpa/voter_set.hpp index 274b734bc0..443d389f59 100644 --- a/core/consensus/grandpa/voter_set.hpp +++ b/core/consensus/grandpa/voter_set.hpp @@ -11,6 +11,7 @@ #include "common/outcome_throw.hpp" #include "consensus/grandpa/common.hpp" #include "consensus/grandpa/types/authority.hpp" +#include "consensus/timeline/types.hpp" namespace kagome::consensus::grandpa { diff --git a/core/consensus/production_consensus.hpp b/core/consensus/production_consensus.hpp index 763ee74900..b79f0a4b3f 100644 --- a/core/consensus/production_consensus.hpp +++ b/core/consensus/production_consensus.hpp @@ -14,7 +14,7 @@ namespace kagome::consensus { enum class ValidatorStatus { NonValidator = 0, - InactiveValidator, + DisabledValidator, Validator, SingleValidator, }; diff --git a/core/consensus/timeline/impl/block_appender_base.cpp b/core/consensus/timeline/impl/block_appender_base.cpp index f8cfe66498..49d1a50b5d 100644 --- a/core/consensus/timeline/impl/block_appender_base.cpp +++ b/core/consensus/timeline/impl/block_appender_base.cpp @@ -75,9 +75,9 @@ namespace kagome::consensus { outcome::result BlockAppenderBase::getSlotInfo( const primitives::BlockHeader &header) const { - OUTCOME_TRY( - slot_number, - babe::getSlot(header)); // TODO(xDimon): Make it consensus agnostic + auto consensus = consensus_selector_.get()->getProductionConsensus(header); + BOOST_ASSERT_MSG(consensus, "Must be returned at least fallback consensus"); + OUTCOME_TRY(slot_number, consensus->getSlot(header)); auto start_time = slots_util_.get()->slotStartTime(slot_number); auto slot_duration = timings_.slot_duration; return outcome::success(SlotInfo{start_time, slot_duration}); diff --git a/core/consensus/timeline/impl/slot_leadership_error.cpp b/core/consensus/timeline/impl/slot_leadership_error.cpp index eba7c0118d..b16105b7d5 100644 --- a/core/consensus/timeline/impl/slot_leadership_error.cpp +++ b/core/consensus/timeline/impl/slot_leadership_error.cpp @@ -9,8 +9,10 @@ OUTCOME_CPP_DEFINE_CATEGORY(kagome::consensus, SlotLeadershipError, e) { using E = kagome::consensus::SlotLeadershipError; switch (e) { - case E::NO_VALIDATOR: + case E::NON_VALIDATOR: return "node is not validator in current epoch"; + case E::DISABLED_VALIDATOR: + return "node is disabled validator till end of epoch"; case E::NO_SLOT_LEADER: return "node is not slot leader in current slot"; case E::BACKING_OFF: diff --git a/core/consensus/timeline/impl/slot_leadership_error.hpp b/core/consensus/timeline/impl/slot_leadership_error.hpp index 52755f7520..a4d0099323 100644 --- a/core/consensus/timeline/impl/slot_leadership_error.hpp +++ b/core/consensus/timeline/impl/slot_leadership_error.hpp @@ -11,7 +11,8 @@ namespace kagome::consensus { enum class SlotLeadershipError { - NO_VALIDATOR = 1, + NON_VALIDATOR = 1, + DISABLED_VALIDATOR, NO_SLOT_LEADER, BACKING_OFF, }; diff --git a/core/consensus/timeline/impl/timeline_impl.cpp b/core/consensus/timeline/impl/timeline_impl.cpp index df99c17f5f..daf4fd564c 100644 --- a/core/consensus/timeline/impl/timeline_impl.cpp +++ b/core/consensus/timeline/impl/timeline_impl.cpp @@ -52,7 +52,7 @@ namespace kagome::consensus { justification_observer, std::shared_ptr scheduler, primitives::events::ChainSubscriptionEnginePtr chain_sub_engine, - primitives::events::BabeStateSubscriptionEnginePtr state_sub_engine, + primitives::events::SyncStateSubscriptionEnginePtr state_sub_engine, std::shared_ptr core_api) : log_(log::createLogger("Timeline", "timeline")), app_state_manager_(std::move(app_state_manager)), @@ -361,7 +361,7 @@ namespace kagome::consensus { return; } - // Start catching up if gap recognized + // Start catching up if a gap recognized if (current_state_ == SyncState::SYNCHRONIZED or current_state_ == SyncState::HEADERS_LOADED) { if (announce.header.number > current_best_block.number + 1) { @@ -371,7 +371,7 @@ namespace kagome::consensus { } // Received announce that has the same block number as ours best, - // or greater by one. Using of simple way to load block + // or greater by one. Using a simple way to load block synchronizer_->syncByBlockHeader( announce.header, peer_id, diff --git a/core/consensus/timeline/impl/timeline_impl.hpp b/core/consensus/timeline/impl/timeline_impl.hpp index 524514eaa9..3eadb29799 100644 --- a/core/consensus/timeline/impl/timeline_impl.hpp +++ b/core/consensus/timeline/impl/timeline_impl.hpp @@ -86,7 +86,7 @@ namespace kagome::consensus { justification_observer, std::shared_ptr scheduler, primitives::events::ChainSubscriptionEnginePtr chain_sub_engine, - primitives::events::BabeStateSubscriptionEnginePtr state_sub_engine, + primitives::events::SyncStateSubscriptionEnginePtr state_sub_engine, std::shared_ptr core_api); /// @see AppStateManager::takeControl @@ -154,7 +154,7 @@ namespace kagome::consensus { std::shared_ptr scheduler_; primitives::events::ChainSubscriptionEnginePtr chain_sub_engine_; primitives::events::ChainSub chain_sub_; - primitives::events::BabeStateSubscriptionEnginePtr state_sub_engine_; + primitives::events::SyncStateSubscriptionEnginePtr state_sub_engine_; std::shared_ptr core_api_; application::SyncMethod sync_method_; diff --git a/core/consensus/timeline/types.hpp b/core/consensus/timeline/types.hpp index 1e78686784..a38758dc58 100644 --- a/core/consensus/timeline/types.hpp +++ b/core/consensus/timeline/types.hpp @@ -25,6 +25,8 @@ namespace kagome::consensus { /// slot number of the block production using SlotNumber = uint64_t; + using AuthorityIndex = uint32_t; + /// duration of single slot in milliseconds struct SlotDuration : public std::chrono::milliseconds { SlotDuration() = default; diff --git a/core/dispute_coordinator/dispute_coordinator.hpp b/core/dispute_coordinator/dispute_coordinator.hpp index a4fbe19675..36f2609c09 100644 --- a/core/dispute_coordinator/dispute_coordinator.hpp +++ b/core/dispute_coordinator/dispute_coordinator.hpp @@ -40,12 +40,6 @@ namespace kagome::dispute { virtual ~DisputeCoordinator() = default; - // virtual void importStatements(CandidateReceipt candidate_receipt, - // SessionIndex session, - // std::vector> - // statements, // FIXME avoid copy - // CbOutcome &&cb) = 0; - /// Fetch a list of all recent disputes the coordinator is aware of. /// These are disputes which have occurred any time in recent sessions, /// and which may have already concluded. diff --git a/core/host_api/host_api.hpp b/core/host_api/host_api.hpp index a72b36cb89..3a8039e4bb 100644 --- a/core/host_api/host_api.hpp +++ b/core/host_api/host_api.hpp @@ -180,7 +180,8 @@ namespace kagome::host_api { ext_trie_blake2_256_ordered_root_version_1( runtime::WasmSpan values_data) = 0; - // TODO(xDimon): add doc-comment + /// Conducts a 256-bit Blake2 trie root formed from the enumerated items + /// considering provided version [[nodiscard]] virtual runtime::WasmPointer ext_trie_blake2_256_ordered_root_version_2( runtime::WasmSpan values_data, runtime::WasmI32 state_version) = 0; diff --git a/core/parachain/approval/approval.hpp b/core/parachain/approval/approval.hpp index 64c0033fd7..bc7acddd26 100644 --- a/core/parachain/approval/approval.hpp +++ b/core/parachain/approval/approval.hpp @@ -195,7 +195,7 @@ namespace kagome::parachain::approval { std::reference_wrapper vrf_output; consensus::SlotNumber slot; - consensus::babe::AuthorityIndex authority_index; + consensus::AuthorityIndex authority_index; /// Get the slot. consensus::SlotNumber getSlot() const { diff --git a/core/parachain/validator/impl/parachain_processor.cpp b/core/parachain/validator/impl/parachain_processor.cpp index 0cd8a48c71..1416057602 100644 --- a/core/parachain/validator/impl/parachain_processor.cpp +++ b/core/parachain/validator/impl/parachain_processor.cpp @@ -113,7 +113,7 @@ namespace kagome::parachain { const application::AppConfiguration &app_config, application::AppStateManager &app_state_manager, primitives::events::ChainSubscriptionEnginePtr chain_sub_engine, - primitives::events::BabeStateSubscriptionEnginePtr babe_status_observable, + primitives::events::SyncStateSubscriptionEnginePtr sync_state_observable, std::shared_ptr query_audi, std::shared_ptr prospective_parachains) : pm_(std::move(pm)), @@ -132,7 +132,7 @@ namespace kagome::parachain { av_store_(std::move(av_store)), parachain_host_(std::move(parachain_host)), app_config_(app_config), - babe_status_observable_(std::move(babe_status_observable)), + sync_state_observable_(std::move(sync_state_observable)), query_audi_{std::move(query_audi)}, per_session_(RefCache::create()), chain_sub_{std::move(chain_sub_engine)}, @@ -151,7 +151,7 @@ namespace kagome::parachain { BOOST_ASSERT(av_store_); BOOST_ASSERT(parachain_host_); BOOST_ASSERT(signer_factory_); - BOOST_ASSERT(babe_status_observable_); + BOOST_ASSERT(sync_state_observable_); BOOST_ASSERT(query_audi_); BOOST_ASSERT(prospective_parachains_); BOOST_ASSERT(worker_pool_handler_); @@ -215,10 +215,10 @@ namespace kagome::parachain { }); // Subscribe to the BABE status observable - babe_status_observer_ = - std::make_shared( - babe_status_observable_, false); - babe_status_observer_->setCallback( + sync_state_observer_ = + std::make_shared( + sync_state_observable_, false); + sync_state_observer_->setCallback( [wself{weak_from_this()}, was_synchronized = false]( auto /*set_id*/, bool &synchronized, @@ -250,8 +250,8 @@ namespace kagome::parachain { } } }); - babe_status_observer_->subscribe( - babe_status_observer_->generateSubscriptionSetId(), + sync_state_observer_->subscribe( + sync_state_observer_->generateSubscriptionSetId(), primitives::events::SyncStateEventType::kSyncState); // Subscribe to the chain events engine @@ -373,9 +373,10 @@ namespace kagome::parachain { StatementDistributionMessage{manifest}}}); } break; default: { - SL_ERROR( - logger_, - "Bug ValidationVersion::V1 should not be used in statement-distribution v2, legacy should have handled this."); + SL_ERROR(logger_, + "Bug ValidationVersion::V1 should not be used in " + "statement-distribution v2, legacy should have handled " + "this."); } break; }; } break; @@ -468,9 +469,9 @@ namespace kagome::parachain { } } break; default: { - SL_ERROR( - logger_, - "Bug ValidationVersion::V1 should not be used in statement-distribution v2, legacy should have handled this"); + SL_ERROR(logger_, + "Bug ValidationVersion::V1 should not be used in " + "statement-distribution v2, legacy should have handled this"); } break; } return {}; @@ -528,11 +529,11 @@ namespace kagome::parachain { .lost = event.lost, }); r.has_error()) { - SL_WARN( - logger_, - "Prospective parachains leaf update failed. (relay_parent={}, error={})", - relay_parent, - r.error()); + SL_WARN(logger_, + "Prospective parachains leaf update failed. (relay_parent={}, " + "error={})", + relay_parent, + r.error()); } backing_store_->onActivateLeaf(relay_parent); @@ -766,7 +767,7 @@ namespace kagome::parachain { if (!isValidatingNode()) { return Error::NOT_A_VALIDATOR; } - if (!babe_status_observer_->get()) { + if (!sync_state_observer_->get()) { return Error::NOT_SYNCHRONIZED; } return outcome::success(); @@ -817,10 +818,10 @@ namespace kagome::parachain { r.has_value()) { minimum_backing_votes = r.value(); } else { - SL_TRACE( - logger_, - "Querying the backing threshold from the runtime is not supported by the current Runtime API. (relay_parent={})", - relay_parent); + SL_TRACE(logger_, + "Querying the backing threshold from the runtime is not " + "supported by the current Runtime API. (relay_parent={})", + relay_parent); } auto per_session_state = per_session_->get_or_insert( @@ -910,14 +911,14 @@ namespace kagome::parachain { statement_store.emplace(per_session_state->value().groups); } - SL_VERBOSE( - logger_, - "Inited new backing task v2.(assigned_para={}, assigned_core={}, our index={}, relay " - "parent={})", - assigned_para, - assigned_core, - validator->validatorIndex(), - relay_parent); + SL_VERBOSE(logger_, + "Inited new backing task v2.(assigned_para={}, " + "assigned_core={}, our index={}, relay " + "parent={})", + assigned_para, + assigned_core, + validator->validatorIndex(), + relay_parent); return RelayParentState{ .prospective_parachains_mode = mode, @@ -1270,12 +1271,12 @@ namespace kagome::parachain { } if (acknowledge) { - SL_TRACE( - logger_, - "immediate ack, known candidate. (candidate hash={}, from={}, local_validator={})", - candidate_hash, - *sender_index, - *relay_parent_state->get().our_index); + SL_TRACE(logger_, + "immediate ack, known candidate. (candidate hash={}, from={}, " + "local_validator={})", + candidate_hash, + *sender_index, + *relay_parent_state->get().our_index); } return ManifestImportSuccess{ @@ -1421,9 +1422,9 @@ namespace kagome::parachain { }}}}); } break; default: { - SL_ERROR( - logger_, - "Bug ValidationVersion::V1 should not be used in statement-distribution v2, legacy should have handled this"); + SL_ERROR(logger_, + "Bug ValidationVersion::V1 should not be used in " + "statement-distribution v2, legacy should have handled this"); return {}; } break; }; @@ -1498,7 +1499,8 @@ namespace kagome::parachain { default: { SL_ERROR( logger_, - "Bug ValidationVersion::V1 should not be used in statement-distribution v2, legacy should have handled this"); + "Bug ValidationVersion::V1 should not be used in " + "statement-distribution v2, legacy should have handled this"); } break; } }); @@ -1637,11 +1639,11 @@ namespace kagome::parachain { return; } - SL_TRACE( - logger_, - "Handling incoming manifest common. (relay_parent={}, candidate_hash={})", - manifest.relay_parent, - manifest.candidate_hash); + SL_TRACE(logger_, + "Handling incoming manifest common. (relay_parent={}, " + "candidate_hash={})", + manifest.relay_parent, + manifest.candidate_hash); ManifestImportSuccessOpt x = handle_incoming_manifest_common( peer_id, manifest.candidate_hash, @@ -1679,11 +1681,11 @@ namespace kagome::parachain { manifest.group_index, manifest.candidate_hash, *relay_parent_state->get().statement_store); - SL_TRACE( - logger_, - "Get ack and statement messages. (relay_parent={}, candidate_hash={})", - manifest.relay_parent, - manifest.candidate_hash); + SL_TRACE(logger_, + "Get ack and statement messages. (relay_parent={}, " + "candidate_hash={})", + manifest.relay_parent, + manifest.candidate_hash); auto messages = acknowledgement_and_statement_messages( peer_id, network::CollationVersion::VStaging, @@ -2753,12 +2755,12 @@ namespace kagome::parachain { post_import_statement_actions(relay_parent, parachain_state, res.value()); if (auto result = res.value()) { if (!assigned_core || result->group_id != *assigned_core) { - SL_TRACE( - logger_, - "Registered statement from not our group(assigned_para our={}, assigned_core our={}, registered={}).", - assigned_para, - assigned_core, - result->group_id); + SL_TRACE(logger_, + "Registered statement from not our group(assigned_para " + "our={}, assigned_core our={}, registered={}).", + assigned_para, + assigned_core, + result->group_id); return; } @@ -2856,11 +2858,11 @@ namespace kagome::parachain { const auto group_index = confirmed_candidate.group_index(); if (!relay_parent_state.per_session_state->value().grid_view) { - SL_TRACE( - logger_, - "Cannot handle backable candidate due to lack of topology. (candidate={}, relay_parent={})", - candidate_hash, - relay_parent); + SL_TRACE(logger_, + "Cannot handle backable candidate due to lack of topology. " + "(candidate={}, relay_parent={})", + candidate_hash, + relay_parent); return; } @@ -2869,12 +2871,12 @@ namespace kagome::parachain { const auto group = relay_parent_state.per_session_state->value().groups.get(group_index); if (!group) { - SL_TRACE( - logger_, - "Handled backed candidate with unknown group? (candidate={}, relay_parent={}, group_index={})", - candidate_hash, - relay_parent, - group_index); + SL_TRACE(logger_, + "Handled backed candidate with unknown group? (candidate={}, " + "relay_parent={}, group_index={})", + candidate_hash, + relay_parent, + group_index); return; } const auto group_size = group->size(); @@ -2952,12 +2954,12 @@ namespace kagome::parachain { BOOST_ASSERT(se); if (!manifest_peers.empty()) { - SL_TRACE( - logger_, - "Sending manifest to v2 peers. (candidate_hash={}, local_validator={}, n_peers={})", - candidate_hash, - *relay_parent_state.our_index, - manifest_peers.size()); + SL_TRACE(logger_, + "Sending manifest to v2 peers. (candidate_hash={}, " + "local_validator={}, n_peers={})", + candidate_hash, + *relay_parent_state.our_index, + manifest_peers.size()); auto message = std::make_shared< network::WireMessage>( kagome::network::vstaging::ValidatorProtocolMessage{ @@ -2969,12 +2971,12 @@ namespace kagome::parachain { } if (!ack_peers.empty()) { - SL_TRACE( - logger_, - "Sending acknowledgement to v2 peers. (candidate_hash={}, local_validator={}, n_peers={})", - candidate_hash, - *relay_parent_state.our_index, - ack_peers.size()); + SL_TRACE(logger_, + "Sending acknowledgement to v2 peers. (candidate_hash={}, " + "local_validator={}, n_peers={})", + candidate_hash, + *relay_parent_state.our_index, + ack_peers.size()); auto message = std::make_shared< network::WireMessage>( kagome::network::vstaging::ValidatorProtocolMessage{ @@ -2986,12 +2988,12 @@ namespace kagome::parachain { } if (!post_statements.empty()) { - SL_TRACE( - logger_, - "Sending statements to v2 peers. (candidate_hash={}, local_validator={}, n_peers={})", - candidate_hash, - *relay_parent_state.our_index, - post_statements.size()); + SL_TRACE(logger_, + "Sending statements to v2 peers. (candidate_hash={}, " + "local_validator={}, n_peers={})", + candidate_hash, + *relay_parent_state.our_index, + post_statements.size()); for (auto &[peers, msg] : post_statements) { if (auto m = @@ -3344,7 +3346,8 @@ namespace kagome::parachain { if (statement_validator_index >= validator_to_group.size()) { SL_TRACE( logger_, - "Invalid validator index. (candidate_hash={}, validator_to_group={}, statement_validator_index={}, n_cores={})", + "Invalid validator index. (candidate_hash={}, validator_to_group={}, " + "statement_validator_index={}, n_cores={})", candidate_hash, validator_to_group.size(), statement_validator_index, @@ -3354,12 +3357,12 @@ namespace kagome::parachain { const auto group_index = validator_to_group[statement_validator_index]; if (!group_index) { - SL_TRACE( - logger_, - "Invalid validator index. Empty group. (candidate_hash={}, statement_validator_index={}, n_cores={})", - candidate_hash, - statement_validator_index, - n_cores); + SL_TRACE(logger_, + "Invalid validator index. Empty group. (candidate_hash={}, " + "statement_validator_index={}, n_cores={})", + candidate_hash, + statement_validator_index, + n_cores); return std::nullopt; } @@ -3367,13 +3370,13 @@ namespace kagome::parachain { group_rotation_info.coreForGroup(*group_index, n_cores); if (size_t(core_index) > n_cores) { - SL_WARN( - logger_, - "Invalid CoreIndex. (candidate_hash={}, core_index={}, validator={}, n_cores={})", - candidate_hash, - core_index, - statement_validator_index, - n_cores); + SL_WARN(logger_, + "Invalid CoreIndex. (candidate_hash={}, core_index={}, " + "validator={}, n_cores={})", + candidate_hash, + core_index, + statement_validator_index, + n_cores); return std::nullopt; } @@ -3395,7 +3398,8 @@ namespace kagome::parachain { [&](const runtime::FreeCore &) -> std::optional { SL_TRACE( logger_, - "Invalid CoreIndex, core is not assigned to any para_id. (candidate_hash={}, core_index={}, validator={}, n_cores={})", + "Invalid CoreIndex, core is not assigned to any para_id. " + "(candidate_hash={}, core_index={}, validator={}, n_cores={})", candidate_hash, core_index, statement_validator_index, @@ -3408,13 +3412,13 @@ namespace kagome::parachain { } if (*assigned_para_id != candidate_para_id) { - SL_TRACE( - logger_, - "Invalid CoreIndex, core is assigned to a different para_id. (candidate_hash={}, core_index={}, validator={}, n_cores={})", - candidate_hash, - core_index, - statement_validator_index, - n_cores); + SL_TRACE(logger_, + "Invalid CoreIndex, core is assigned to a different para_id. " + "(candidate_hash={}, core_index={}, validator={}, n_cores={})", + candidate_hash, + core_index, + statement_validator_index, + n_cores); return std::nullopt; } return core_index; @@ -4079,13 +4083,13 @@ namespace kagome::parachain { const SignedFullStatementWithPVD &statement) { const CandidateHash candidate_hash = candidateHashFrom(getPayload(statement)); - SL_TRACE( - logger_, - "Sharing statement. (relay parent={}, candidate hash={}, our_index={}, statement_ix={})", - relay_parent, - candidate_hash, - *per_relay_parent.our_index, - statement.payload.ix); + SL_TRACE(logger_, + "Sharing statement. (relay parent={}, candidate hash={}, " + "our_index={}, statement_ix={})", + relay_parent, + candidate_hash, + *per_relay_parent.our_index, + statement.payload.ix); BOOST_ASSERT(per_relay_parent.our_index); @@ -4301,14 +4305,14 @@ namespace kagome::parachain { return; } if (!validation_result) { - SL_WARN( - self->logger_, - "Candidate {} on relay_parent {}, para_id {} validation failed with " - "error: {}", - candidate_hash, - candidate.descriptor.relay_parent, - candidate.descriptor.para_id, - validation_result.error()); + SL_WARN(self->logger_, + "Candidate {} on relay_parent {}, para_id {} validation failed " + "with " + "error: {}", + candidate_hash, + candidate.descriptor.relay_parent, + candidate.descriptor.para_id, + validation_result.error()); return; } diff --git a/core/parachain/validator/parachain_processor.hpp b/core/parachain/validator/parachain_processor.hpp index 67be18a91c..7fe7831209 100644 --- a/core/parachain/validator/parachain_processor.hpp +++ b/core/parachain/validator/parachain_processor.hpp @@ -149,8 +149,8 @@ namespace kagome::parachain { const application::AppConfiguration &app_config, application::AppStateManager &app_state_manager, primitives::events::ChainSubscriptionEnginePtr chain_sub_engine, - primitives::events::BabeStateSubscriptionEnginePtr - babe_status_observable, + primitives::events::SyncStateSubscriptionEnginePtr + sync_state_observable, std::shared_ptr query_audi, std::shared_ptr prospective_parachains); ~ParachainProcessorImpl() = default; @@ -1014,8 +1014,8 @@ namespace kagome::parachain { std::shared_ptr av_store_; std::shared_ptr parachain_host_; const application::AppConfiguration &app_config_; - primitives::events::BabeStateSubscriptionEnginePtr babe_status_observable_; - primitives::events::BabeStateEventSubscriberPtr babe_status_observer_; + primitives::events::SyncStateSubscriptionEnginePtr sync_state_observable_; + primitives::events::SyncStateEventSubscriberPtr sync_state_observer_; std::shared_ptr query_audi_; std::shared_ptr> per_session_; diff --git a/core/primitives/event_types.hpp b/core/primitives/event_types.hpp index 14edcdf12d..b0bc4e29b9 100644 --- a/core/primitives/event_types.hpp +++ b/core/primitives/event_types.hpp @@ -241,15 +241,15 @@ namespace kagome::primitives::events { using ChainEventSubscriber = ChainSubscriptionEngine::SubscriberType; using ChainEventSubscriberPtr = std::shared_ptr; - using BabeStateSubscriptionEngine = subscription::SubscriptionEngine< + using SyncStateSubscriptionEngine = subscription::SubscriptionEngine< primitives::events::SyncStateEventType, bool, primitives::events::SyncStateEventParams>; - using BabeStateSubscriptionEnginePtr = - std::shared_ptr; + using SyncStateSubscriptionEnginePtr = + std::shared_ptr; - using BabeStateEventSubscriber = BabeStateSubscriptionEngine::SubscriberType; - using BabeStateEventSubscriberPtr = std::shared_ptr; + using SyncStateEventSubscriber = SyncStateSubscriptionEngine::SubscriberType; + using SyncStateEventSubscriberPtr = std::shared_ptr; using ExtrinsicSubscriptionEngine = subscription::SubscriptionEngine< SubscribedExtrinsicId, diff --git a/core/runtime/runtime_api/babe_api.hpp b/core/runtime/runtime_api/babe_api.hpp index a99e8ea392..a90ca5b6ba 100644 --- a/core/runtime/runtime_api/babe_api.hpp +++ b/core/runtime/runtime_api/babe_api.hpp @@ -64,6 +64,10 @@ namespace kagome::runtime { const primitives::BlockHash &block_hash, consensus::babe::EquivocationProof equivocation_proof, consensus::babe::OpaqueKeyOwnershipProof key_owner_proof) = 0; + + /// Returns a list of all disabled validators at the given block. + virtual outcome::result> + disabled_validators(const primitives::BlockHash &block) = 0; }; } // namespace kagome::runtime diff --git a/core/runtime/runtime_api/impl/babe_api.cpp b/core/runtime/runtime_api/impl/babe_api.cpp index 6bd7e2828e..7db4449ae2 100644 --- a/core/runtime/runtime_api/impl/babe_api.cpp +++ b/core/runtime/runtime_api/impl/babe_api.cpp @@ -6,6 +6,7 @@ #include "runtime/runtime_api/impl/babe_api.hpp" +#include "runtime/common/runtime_execution_error.hpp" #include "runtime/executor.hpp" namespace kagome::runtime { @@ -52,4 +53,16 @@ namespace kagome::runtime { key_owner_proof); } + + outcome::result> + BabeApiImpl::disabled_validators(const primitives::BlockHash &block) { + OUTCOME_TRY(ctx, executor_->ctx().ephemeralAt(block)); + auto res = executor_->call>( + ctx, "ParachainHost_disabled_validators"); + if (res.has_error() + and res.error() == RuntimeExecutionError::EXPORT_FUNCTION_NOT_FOUND) { + return std::vector{}; + } + return res; + } } // namespace kagome::runtime diff --git a/core/runtime/runtime_api/impl/babe_api.hpp b/core/runtime/runtime_api/impl/babe_api.hpp index 36d39e7805..87a0f93b01 100644 --- a/core/runtime/runtime_api/impl/babe_api.hpp +++ b/core/runtime/runtime_api/impl/babe_api.hpp @@ -33,6 +33,10 @@ namespace kagome::runtime { consensus::babe::EquivocationProof equivocation_proof, consensus::babe::OpaqueKeyOwnershipProof key_owner_proof) override; + /// Returns a list of all disabled validators at the given block. + outcome::result> disabled_validators( + const primitives::BlockHash &block) override; + private: std::shared_ptr executor_; }; diff --git a/test/core/api/service/author/author_api_test.cpp b/test/core/api/service/author/author_api_test.cpp index 3f6b285d6c..ba166bdec4 100644 --- a/test/core/api/service/author/author_api_test.cpp +++ b/test/core/api/service/author/author_api_test.cpp @@ -144,7 +144,7 @@ struct AuthorApiTest : public ::testing::Test { store = std::make_shared(); key_store = KeyFileStorage::createAt("test_chain_43/keystore").value(); - key_pair = generateSr25519Keypair(); + key_pair = generateSr25519Keypair(0); ASSERT_OUTCOME_SUCCESS_TRY( key_store->saveKeyPair(KeyTypes::BABE, std::span(key_pair.public_key).first<32>(), diff --git a/test/core/consensus/babe/babe_block_validator_test.cpp b/test/core/consensus/babe/babe_block_validator_test.cpp index 16c5e1643d..4d1e796714 100644 --- a/test/core/consensus/babe/babe_block_validator_test.cpp +++ b/test/core/consensus/babe/babe_block_validator_test.cpp @@ -9,18 +9,22 @@ #include "consensus/babe/impl/babe_block_validator_impl.hpp" #include "consensus/babe/impl/babe_digests_util.hpp" #include "consensus/babe/types/seal.hpp" +#include "mock/core/application/app_state_manager_mock.hpp" #include "mock/core/consensus/babe/babe_config_repository_mock.hpp" #include "mock/core/consensus/timeline/slots_util_mock.hpp" #include "mock/core/crypto/hasher_mock.hpp" #include "mock/core/crypto/sr25519_provider_mock.hpp" #include "mock/core/crypto/vrf_provider_mock.hpp" +#include "mock/core/runtime/babe_api_mock.hpp" #include "testutil/lazy.hpp" #include "testutil/outcome.hpp" #include "testutil/prepare_loggers.hpp" #include "testutil/sr25519_utils.hpp" +using kagome::application::AppStateManagerMock; using kagome::common::Buffer; using kagome::common::uint256_to_le_bytes; +using kagome::consensus::AuthorityIndex; using kagome::consensus::SlotNumber; using kagome::consensus::SlotsUtil; using kagome::consensus::SlotsUtilMock; @@ -28,7 +32,6 @@ using kagome::consensus::Threshold; using kagome::consensus::babe::Authorities; using kagome::consensus::babe::Authority; using kagome::consensus::babe::AuthorityId; -using kagome::consensus::babe::AuthorityIndex; using kagome::consensus::babe::BabeBlockHeader; using kagome::consensus::babe::BabeBlockValidatorImpl; using kagome::consensus::babe::BabeConfigRepositoryMock; @@ -52,6 +55,8 @@ using kagome::primitives::BlockHeader; using kagome::primitives::ConsensusEngineId; using kagome::primitives::Extrinsic; using kagome::primitives::PreRuntime; +using kagome::primitives::events::SyncStateSubscriptionEngine; +using kagome::runtime::BabeApiMock; using Seal = kagome::consensus::babe::Seal; using ValidatingError = kagome::consensus::babe::BabeBlockValidatorImpl::ValidationError; @@ -71,6 +76,7 @@ class BabeBlockValidatorTest : public testing::Test { } void SetUp() override { + app_state_manager = std::make_shared(); slots_util = std::make_shared(); ON_CALL(*slots_util, slotToEpoch(_, _)).WillByDefault(Return(1)); @@ -88,15 +94,21 @@ class BabeBlockValidatorTest : public testing::Test { sr25519_provider = std::make_shared(); vrf_provider = std::make_shared(); + babe_api = std::make_shared(); + state_sub_engine = std::make_shared(); block_validator = std::make_shared( + app_state_manager, testutil::sptr_to_lazy(slots_util), config_repo, hasher, sr25519_provider, - vrf_provider); + vrf_provider, + babe_api, + state_sub_engine); } + std::shared_ptr app_state_manager; std::shared_ptr slots_util; std::shared_ptr our_keypair; std::shared_ptr other_keypair; @@ -105,6 +117,8 @@ class BabeBlockValidatorTest : public testing::Test { std::shared_ptr hasher; std::shared_ptr sr25519_provider; std::shared_ptr vrf_provider; + std::shared_ptr babe_api; + std::shared_ptr state_sub_engine; std::shared_ptr block_validator; // fields for block diff --git a/test/core/consensus/babe/babe_test.cpp b/test/core/consensus/babe/babe_test.cpp index c86df2ecb9..20114a13c9 100644 --- a/test/core/consensus/babe/babe_test.cpp +++ b/test/core/consensus/babe/babe_test.cpp @@ -61,6 +61,7 @@ using kagome::common::BufferView; using kagome::common::MainThreadPool; using kagome::common::uint256_to_le_bytes; using kagome::common::WorkerThreadPool; +using kagome::consensus::AuthorityIndex; using kagome::consensus::BlockProductionError; using kagome::consensus::Duration; using kagome::consensus::EpochLength; @@ -75,7 +76,6 @@ using kagome::consensus::ValidatorStatus; using kagome::consensus::babe::Authorities; using kagome::consensus::babe::Authority; using kagome::consensus::babe::AuthorityId; -using kagome::consensus::babe::AuthorityIndex; using kagome::consensus::babe::Babe; using kagome::consensus::babe::BabeBlockHeader; using kagome::consensus::babe::BabeBlockValidator; @@ -187,13 +187,21 @@ class BabeTest : public testing::Test { // add initialization logic timings = {60ms, 2}; - our_keypair = std::make_shared(generateSr25519Keypair()); - other_keypair = std::make_shared(generateSr25519Keypair()); + + our_authority_index = 0; + other_authority_index = 1; + our_keypair = std::make_shared( + generateSr25519Keypair(our_authority_index)); + other_keypair = std::make_shared( + generateSr25519Keypair(other_authority_index)); babe_config = std::make_shared(); babe_config->slot_duration = timings.slot_duration; babe_config->randomness.fill(0); - babe_config->authorities = {Authority{{our_keypair->public_key}, 1}, - Authority{{other_keypair->public_key}, 1}}; + babe_config->authorities.resize(2); + babe_config->authorities[our_authority_index] = + Authority{{our_keypair->public_key}, 1}; + babe_config->authorities[other_authority_index] = + Authority{{other_keypair->public_key}, 1}; babe_config->leadership_rate = {1, 4}; babe_config->epoch_length = timings.epoch_length; @@ -202,7 +210,8 @@ class BabeTest : public testing::Test { session_keys = std::make_shared(); ON_CALL(*session_keys, getBabeKeyPair(babe_config->authorities)) - .WillByDefault(Return(std::make_pair(our_keypair, 1))); + .WillByDefault( + Return(std::make_pair(our_keypair, our_authority_index))); lottery = std::make_shared(); @@ -315,7 +324,10 @@ class BabeTest : public testing::Test { std::shared_ptr babe_config; + AuthorityIndex our_authority_index = 0; std::shared_ptr our_keypair; + + AuthorityIndex other_authority_index = 1; std::shared_ptr other_keypair; static constexpr EpochNumber uninitialized_epoch = @@ -374,6 +386,9 @@ class BabeTest : public testing::Test { }; TEST_F(BabeTest, Setup) { + EXPECT_CALL(*babe_api, disabled_validators(_)) + .WillOnce(Return(std::vector{})); + ASSERT_OUTCOME_ERROR(babe->getSlot(genesis_block_header), DigestError::GENESIS_BLOCK_CAN_NOT_HAVE_DIGESTS); @@ -404,7 +419,31 @@ TEST_F(BabeTest, NonValidator) { ValidatorStatus::NonValidator); ASSERT_OUTCOME_ERROR(babe->processSlot(slot, best_block_info), - SlotLeadershipError::NO_VALIDATOR); + SlotLeadershipError::NON_VALIDATOR); +} + +TEST_F(BabeTest, DisabledValidator) { + SlotNumber slot = new_block_slot; + EpochNumber epoch = 0; + + EXPECT_CALL(*slots_util, timeToSlot(_)).WillOnce(Return(slot)); + EXPECT_CALL(*slots_util, slotToEpoch(best_block_info, slot)) + .WillOnce(Return(outcome::success(epoch))); + + EXPECT_CALL(*babe_api, disabled_validators(_)) + .WillRepeatedly(Return(std::vector{our_authority_index})); + + EXPECT_CALL(*lottery, getEpoch()) + .WillOnce(Return(uninitialized_epoch)) + .WillRepeatedly(Return(epoch)); + EXPECT_CALL(*lottery, changeEpoch(epoch, best_block_info)) + .WillOnce(Return(true)); + + EXPECT_EQ(babe->getValidatorStatus(best_block_info, slot), + ValidatorStatus::DisabledValidator); + + ASSERT_OUTCOME_ERROR(babe->processSlot(slot, best_block_info), + SlotLeadershipError::DISABLED_VALIDATOR); } TEST_F(BabeTest, NoSlotLeader) { @@ -415,6 +454,9 @@ TEST_F(BabeTest, NoSlotLeader) { EXPECT_CALL(*slots_util, slotToEpoch(best_block_info, slot)) .WillOnce(Return(outcome::success(epoch))); + EXPECT_CALL(*babe_api, disabled_validators(_)) + .WillRepeatedly(Return(std::vector{})); + EXPECT_CALL(*lottery, getEpoch()) .WillOnce(Return(uninitialized_epoch)) .WillRepeatedly(Return(epoch)); @@ -438,6 +480,9 @@ TEST_F(BabeTest, SlotLeader) { EXPECT_CALL(*slots_util, slotToEpoch(best_block_info, slot)) .WillOnce(Return(outcome::success(epoch))); + EXPECT_CALL(*babe_api, disabled_validators(_)) + .WillRepeatedly(Return(std::vector{})); + EXPECT_CALL(*lottery, getEpoch()) .WillOnce(Return(uninitialized_epoch)) .WillRepeatedly(Return(epoch)); diff --git a/test/core/consensus/babe/threshold_util_test.cpp b/test/core/consensus/babe/threshold_util_test.cpp index d7b0bed2c3..48c7516557 100644 --- a/test/core/consensus/babe/threshold_util_test.cpp +++ b/test/core/consensus/babe/threshold_util_test.cpp @@ -23,7 +23,7 @@ TEST(ThresholdTest, OutputAsInGossamer) { std::pair c; c.first = 5; c.second = 17; - consensus::babe::AuthorityIndex authority_index{3}; + consensus::AuthorityIndex authority_index{3}; consensus::babe::Authorities authorities; authorities.push_back(consensus::babe::Authority{.id = {}, .weight = 3}); authorities.push_back(consensus::babe::Authority{.id = {}, .weight = 1}); diff --git a/test/core/consensus/timeline/block_executor_test.cpp b/test/core/consensus/timeline/block_executor_test.cpp index c4b2c3e8f7..829a236e09 100644 --- a/test/core/consensus/timeline/block_executor_test.cpp +++ b/test/core/consensus/timeline/block_executor_test.cpp @@ -249,6 +249,7 @@ TEST_F(BlockExecutorTest, JustificationFollowDigests) { kagome::primitives::BlockHash parent_hash = "parent_hash"_hash256; kagome::primitives::BlockHash some_hash = "some_hash"_hash256; + kagome::consensus::SlotNumber slot = 123; kagome::primitives::BlockHeader header{ 42, // number parent_hash, // parent @@ -258,7 +259,7 @@ TEST_F(BlockExecutorTest, JustificationFollowDigests) { kagome::primitives::PreRuntime{{ kagome::primitives::kBabeEngineId, Buffer{scale::encode(BabeBlockHeader{.authority_index = 1, - .slot_number = 1}) + .slot_number = slot}) .value()}, }}, kagome::primitives::Consensus{ScheduledChange{authorities, 0}}, @@ -268,6 +269,7 @@ TEST_F(BlockExecutorTest, JustificationFollowDigests) { }}}, some_hash // hash }; + ON_CALL(*production_consensus_, getSlot(_)).WillByDefault(Return(0)); kagome::primitives::Justification justification{.data = "justification_data"_buf}; diff --git a/test/core/consensus/timeline/timeline_test.cpp b/test/core/consensus/timeline/timeline_test.cpp index 43f3cfd8b2..14553abaa9 100644 --- a/test/core/consensus/timeline/timeline_test.cpp +++ b/test/core/consensus/timeline/timeline_test.cpp @@ -68,8 +68,8 @@ using kagome::primitives::Digest; using kagome::primitives::Extrinsic; using kagome::primitives::PreRuntime; using kagome::primitives::detail::DigestItemCommon; -using kagome::primitives::events::BabeStateSubscriptionEngine; using kagome::primitives::events::ChainSubscriptionEngine; +using kagome::primitives::events::SyncStateSubscriptionEngine; using kagome::runtime::CoreMock; using kagome::storage::trie::TrieStorageMock; using libp2p::basic::SchedulerMock; @@ -159,7 +159,7 @@ class TimelineTest : public testing::Test { scheduler = std::make_shared(); core_api = std::make_shared(); chain_sub_engine = std::make_shared(); - state_sub_engine = std::make_shared(); + state_sub_engine = std::make_shared(); timeline = std::make_shared( app_config, @@ -197,7 +197,7 @@ class TimelineTest : public testing::Test { std::shared_ptr justification_observer; std::shared_ptr scheduler; std::shared_ptr chain_sub_engine; - std::shared_ptr state_sub_engine; + std::shared_ptr state_sub_engine; std::shared_ptr core_api; std::shared_ptr timeline; diff --git a/test/mock/core/runtime/babe_api_mock.hpp b/test/mock/core/runtime/babe_api_mock.hpp index f3ed1801a5..48f82f60a6 100644 --- a/test/mock/core/runtime/babe_api_mock.hpp +++ b/test/mock/core/runtime/babe_api_mock.hpp @@ -38,6 +38,11 @@ namespace kagome::runtime { consensus::babe::EquivocationProof, consensus::babe::OpaqueKeyOwnershipProof), (override)); + + MOCK_METHOD(outcome::result>, + disabled_validators, + (const primitives::BlockHash &block), + (override)); }; } // namespace kagome::runtime diff --git a/test/testutil/sr25519_utils.hpp b/test/testutil/sr25519_utils.hpp index 47bbb662e4..7ff8174d45 100644 --- a/test/testutil/sr25519_utils.hpp +++ b/test/testutil/sr25519_utils.hpp @@ -13,10 +13,14 @@ namespace sr25519_constants = kagome::crypto::constants::sr25519; /** * Generate a SR25519 with some seed */ -kagome::crypto::Sr25519Keypair generateSr25519Keypair() { +kagome::crypto::Sr25519Keypair generateSr25519Keypair( + kagome::consensus::AuthorityIndex auth_id_as_seed) { namespace crypto = kagome::crypto; std::array seed{}; - seed.fill(1); + for (size_t i = 0; i < seed.size(); ++i) { + seed[i] = reinterpret_cast( // NOLINT + &auth_id_as_seed)[i % sizeof(auth_id_as_seed)]; + } std::array kp{}; sr25519_keypair_from_seed(kp.data(), seed.data()); crypto::Sr25519Keypair keypair{