// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! Helpers for offchain worker election.
use codec::Decode;
use crate::{
Call, CompactAssignments, Module, NominatorIndex, OffchainAccuracy, Trait, ValidatorIndex,
};
use frame_system::offchain::SubmitTransaction;
use sp_phragmen::{
build_support_map, evaluate_support, reduce, Assignment, ExtendedBalance, PhragmenResult,
PhragmenScore, equalize,
};
use sp_runtime::offchain::storage::StorageValueRef;
use sp_runtime::{PerThing, RuntimeDebug, traits::{TrailingZeroInput, Zero}};
use frame_support::{debug, traits::Get};
use sp_std::{convert::TryInto, prelude::*};
/// Error types related to the offchain election machinery.
#[derive(RuntimeDebug)]
pub enum OffchainElectionError {
/// Phragmen election returned None. This means less candidate that minimum number of needed
/// validators were present. The chain is in trouble and not much that we can do about it.
ElectionFailed,
/// Submission to the transaction pool failed.
PoolSubmissionFailed,
/// The snapshot data is not available.
SnapshotUnavailable,
/// Error from phragmen crate. This usually relates to compact operation.
PhragmenError(sp_phragmen::Error),
/// One of the computed winners is invalid.
InvalidWinner,
}
impl From for OffchainElectionError {
fn from(e: sp_phragmen::Error) -> Self {
Self::PhragmenError(e)
}
}
/// Storage key used to store the persistent offchain worker status.
pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/staking-election/";
/// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice
/// within a window of 5 blocks.
pub(crate) const OFFCHAIN_REPEAT: u32 = 5;
/// Default number of blocks for which the unsigned transaction should stay in the pool
pub(crate) const DEFAULT_LONGEVITY: u64 = 25;
/// Checks if an execution of the offchain worker is permitted at the given block number, or not.
///
/// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we
/// don't run twice within a window of length [`OFFCHAIN_REPEAT`].
///
/// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise.
pub(crate) fn set_check_offchain_execution_status(
now: T::BlockNumber,
) -> Result<(), &'static str> {
let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB);
let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT);
let mutate_stat =
storage.mutate::<_, &'static str, _>(|maybe_head: Option