use crate::{
crypto::*, types::*, AffidavitKeys, Config, CurrentSession, ElectsPreparedBy, Error,
FinalityAfter, FinalityTicks, Internals, Pallet, SessionStartAt,
};
use frame_suite::{ForksHandler, blockchain::*, routines::*};
use frame_support::traits::EstimateNextSessionRotation;
use frame_system::{
offchain::{AppCrypto, SendSignedTransaction, SignedPayload, Signer},
pallet_prelude::BlockNumberFor,
};
use sp_runtime::{
DispatchError, RuntimeAppPublic, traits::{IdentifyAccount, One, Saturating}
};
use scale_info::prelude::{format, string::String};
pub const LOG_TARGET_AFDT: Option<&'static str> = Some("AFFIDAVIT");
pub const LOG_TARGET_ELEC: Option<&'static str> = Some("ELECTION");
pub const ACTIVE_AFDT_KEY: &'static [u8] = b"ACTIVE_AFDT_KEY";
const EMOJI_DEBUG: &str = "๐";
const EMOJI_ERROR: &str = "๐จ";
const EMOJI_INFO: &str = "๐ฃ";
const EMOJI_WARN: &str = "โ ๏ธ";
#[inline(always)]
fn level_emoji(level: &LogLevel) -> &'static str {
match level {
LogLevel::Debug => EMOJI_DEBUG,
LogLevel::Error => EMOJI_ERROR,
LogLevel::Info => EMOJI_INFO,
LogLevel::Warn => EMOJI_WARN,
}
}
pub fn std_fmt<T: Config>(
timestamp: BlockNumberFor<T>,
level: &LogLevel,
target: &str,
message: &str,
) -> String {
format!(
"๐งฑ [{:?}] {} [{:?}] ๐ฏ [{}] ๐งพ {}",
timestamp,
level_emoji(level),
level,
target,
message
)
}
impl<T: Config> OffchainStorageError<ForkAware<T, ValueHash, InitAffidavitKey<T>, Pallet<T>>>
for InitAffidavitKey<T>
{
type Error = Error<T>;
fn decode_failed() -> Self::Error {
Error::<T>::ActiveAfdtKeySpeculativeHashDecodeFail
}
fn concurrent_mutation() -> Self::Error {
Error::<T>::ActiveAfdtKeySpeculativeHashConcurrentMutation
}
}
impl<T: Config> OffchainStorageError<Persistent<T, Ledger<T, AffidavitId<T>>, InitAffidavitKey<T>>>
for InitAffidavitKey<T>
{
type Error = Error<T>;
fn decode_failed() -> Self::Error {
Error::<T>::ActiveAfdtKeyFinalizedValueDecodeFail
}
fn concurrent_mutation() -> Self::Error {
Error::<T>::ActiveAfdtKeyFinalizedValueConcurrentMutation
}
}
impl<T: Config> FinalizedOffchainStorageError<T, AffidavitId<T>> for InitAffidavitKey<T> {
type Error = Error<T>;
fn hanging_hash() -> Self::Error {
Error::<T>::ActiveAfdtKeySpeculativeHangingHash
}
fn hanging_value() -> Self::Error {
Error::<T>::ActiveAfdtKeyFinalizedHangingValue
}
}
impl<T: Config> FinalizedPolicy<T> for InitAffidavitKey<T> {
fn finality_after() -> <T as pallet_timestamp::Config>::Moment {
FinalityAfter::<T>::get()
}
fn finality_ticks() -> BlockNumberFor<T> {
FinalityTicks::<T>::get()
}
}
impl<T: Config> Routines<BlockNumberFor<T>> for InitAffidavitKey<T> {
fn can_run(&self) -> Result<(), Self::Logger> {
let result =
Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::get(ACTIVE_AFDT_KEY, LOG_TARGET_AFDT, None);
let afdt_key = match result {
Ok(None) => return Ok(()),
Ok(Some(Confidence::Safe(key))) => key,
Ok(Some(_)) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::ActiveAfdtKeyNotYetFinalized.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Err(_) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
};
let all_keys =
<<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
as RuntimeAppPublic>::all();
if all_keys.is_empty() {
return Ok(());
}
for key in all_keys.into_iter() {
let generic_pub:
<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
key.into();
let public: T::Public = generic_pub.into();
let account: AffidavitId<T> = public.clone().into_account().into();
if account == afdt_key {
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::AffidavitKeyExists.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
}
Ok(())
}
fn run_service(&self) -> Result<(), Self::Logger> {
if let Err(e) = Self::can_run(&self) {
if e == Error::<T>::AffidavitKeyExists.into() {
return Ok(());
}
return Err(e);
}
let key =
<<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
as RuntimeAppPublic>::generate_pair(None);
let generic_pub: <T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
key.into();
let public: T::Public = generic_pub.into();
let account: AffidavitId<T> = public.clone().into_account().into();
if Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::insert(
ACTIVE_AFDT_KEY,
&account,
LOG_TARGET_AFDT,
None,
)
.is_err()
{
let block = self.at;
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::SetNewAffidavitKeyFailed.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
Ok(())
}
fn on_ran_service(&self) {
<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::InitAffidavitKeyRoutineSuccess.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
);
}
}
impl<T: Config> RoutineOf<T::Public, BlockNumberFor<T>> for TryElection<T> {
fn who(at: &BlockNumberFor<T>) -> Result<T::Public, Self::Logger> {
let who = <DeclareAffidavit<T> as RoutineOf<T::Public, BlockNumberFor<T>>>::who(at)?;
Ok(who)
}
}
impl<T: Config> Routines<BlockNumberFor<T>> for TryElection<T> {
fn can_run(&self) -> Result<(), Self::Logger> {
if let Err(e) =
<Internals<T> as ElectAuthors<AuthorOf<T>, ElectionVia<T>>>::can_process_election(&None)
{
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&e,
self.at,
LOG_TARGET_ELEC,
Some(std_fmt::<T>),
));
}
Ok(())
}
fn run_service(&self) -> Result<(), Self::Logger> {
if let Err(_) = Self::can_run(&self) {
return Ok(());
}
let for_session = CurrentSession::<T>::get().saturating_add(One::one());
let afdt_pub: AffidavitId<T> = self.by.clone().into_account().into();
let Some(author) =
AffidavitKeys::<T>::get((for_session.saturating_add(One::one()), afdt_pub))
else {
<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::AffidavitKeyForDeclaration.into(),
self.at,
LOG_TARGET_ELEC,
Some(std_fmt::<T>),
);
return Ok(());
};
if let Some((runner, _)) = ElectsPreparedBy::<T>::get(for_session) {
if author == runner {
return Ok(());
}
}
let payload = ElectionPayload {
public: self.by.clone(),
};
let Some(signature) =
<ElectionPayload<T::Public> as SignedPayload<T>>::sign::<T::AffidavitCrypto>(&payload)
else {
return Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::CannotSignElectionTxPayload.into(),
self.at,
LOG_TARGET_ELEC,
Some(std_fmt::<T>),
));
};
let signer = Signer::<T, T::AffidavitCrypto>::any_account();
let result = signer.send_signed_transaction(|_| {
<T as crate::Config>::RuntimeCall::from(crate::Call::elect {
payload: payload.clone(),
signature: signature.clone(),
})
.into()
});
match result {
Some((_, Ok(_))) => Ok(()),
Some((_, Err(_))) => Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ExtrinsicFailedToElectAuthors.into(),
self.at,
LOG_TARGET_ELEC,
Some(std_fmt::<T>),
)),
None => Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::CannotSubmitElectionTx.into(),
self.at,
LOG_TARGET_ELEC,
Some(std_fmt::<T>),
)),
}
}
fn on_ran_service(&self) {
<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::TryElectionRoutineSuccess.into(),
self.at,
LOG_TARGET_ELEC,
Some(std_fmt::<T>),
);
}
}
pub const NEXT_AFDT_KEY: &'static [u8] = b"NEXT_AFDT_KEY";
impl<T: Config> OffchainStorageError<ForkAware<T, ValueHash, DeclareAffidavit<T>, Pallet<T>>>
for DeclareAffidavit<T>
{
type Error = Error<T>;
fn decode_failed() -> Self::Error {
Error::<T>::NextAfdtKeySpeculativeHashDecodeFail
}
fn concurrent_mutation() -> Self::Error {
Error::<T>::NextAfdtKeySpeculativeHashConcurrentMutation
}
}
impl<T: Config> OffchainStorageError<Persistent<T, Ledger<T, AffidavitId<T>>, DeclareAffidavit<T>>>
for DeclareAffidavit<T>
{
type Error = Error<T>;
fn decode_failed() -> Self::Error {
Error::<T>::NextAfdtKeyFinalizedValueDecodeFail
}
fn concurrent_mutation() -> Self::Error {
Error::<T>::NextAfdtKeyFinalizedValueConcurrentMutation
}
}
impl<T: Config> FinalizedOffchainStorageError<T, AffidavitId<T>> for DeclareAffidavit<T> {
type Error = Error<T>;
fn hanging_hash() -> Self::Error {
Error::<T>::NextAfdtKeySpeculativeHangingHash
}
fn hanging_value() -> Self::Error {
Error::<T>::NextAfdtKeyFinalizedHangingValue
}
}
impl<T: Config> FinalizedPolicy<T> for DeclareAffidavit<T> {
fn finality_after() -> <T as pallet_timestamp::Config>::Moment {
<InitAffidavitKey<T> as FinalizedPolicy<T>>::finality_after()
}
fn finality_ticks() -> BlockNumberFor<T> {
<InitAffidavitKey<T> as FinalizedPolicy<T>>::finality_ticks()
}
}
impl<T: Config> RoutineOf<T::Public, BlockNumberFor<T>> for DeclareAffidavit<T> {
fn who(at: &BlockNumberFor<T>) -> Result<T::Public, Self::Logger> {
let result = Finalized::<T, AffidavitId<T>, InitAffidavitKey<T>, Pallet<T>>::get(
ACTIVE_AFDT_KEY,
LOG_TARGET_AFDT,
None,
);
let afdt_key = match result {
Ok(Some(Confidence::Safe(key))) => key,
Ok(None) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ExpectedToHoldActiveAffidavitKey.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Ok(Some(_)) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::ActiveAfdtKeyNotYetFinalized.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Err(_) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
};
let all_keys =
<<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
as RuntimeAppPublic>::all();
for key in all_keys.into_iter() {
let generic_pub:
<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
key.into();
let public: T::Public = generic_pub.into();
let account: AffidavitId<T> = public.clone().into_account().into();
if account == afdt_key {
return Ok(public);
}
}
Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ExpectedActiveAffidavitKeyPairNotFound.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
}
impl<T: Config> Routines<BlockNumberFor<T>> for DeclareAffidavit<T> {
fn can_run(&self) -> Result<(), Self::Logger> {
let afdt_pub = &self.by;
let block = self.at;
let result =
Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::get(NEXT_AFDT_KEY, LOG_TARGET_AFDT, None);
match result {
Ok(None) => {
let new_key =
<<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
as RuntimeAppPublic>::generate_pair(None);
let public: T::Public = {
let generic_pub:
<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
new_key.into();
generic_pub.into()
};
let new_afdt_key = public.clone().into_account();
if Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::insert(
NEXT_AFDT_KEY,
&new_afdt_key,
LOG_TARGET_AFDT,
None,
)
.is_err()
{
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::SetNextAffidavitKeyFailed.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::NextAfdtKeyNotYetFinalized.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
Ok(Some(Confidence::Safe(_))) => {}
Ok(Some(_)) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::NextAfdtKeyNotYetFinalized.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Err(_) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
}
if let Err(e) =
<Pallet<T> as ElectionAffidavits<AffidavitId<T>, ElectionVia<T>>>::can_submit_affidavit(
(&afdt_pub.clone().into_account()).into(),
)
{
return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
&e,
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
Ok(())
}
fn run_service(&self) -> Result<(), Self::Logger> {
Self::can_run(self)?;
let afdt_key = &self.by;
let block = self.at;
let result =
Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::get(NEXT_AFDT_KEY, LOG_TARGET_AFDT, None);
let next_afdt_key = match result {
Ok(Some(Confidence::Safe(key))) => key,
Ok(Some(_)) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Ok(None) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Err(_) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
};
let payload = AffidavitPayload {
public: afdt_key.clone(),
rotate: next_afdt_key.clone(),
};
let Some(signature) =
<AffidavitPayload<T::Public, AffidavitId<T>> as SignedPayload<T>>::sign::<
T::AffidavitCrypto,
>(&payload)
else {
return Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::CannotSignAffidavitTxPayload.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
};
let signer = Signer::<T, T::AffidavitCrypto>::any_account();
let result = signer.send_signed_transaction(|_| {
<T as crate::Config>::RuntimeCall::from(crate::Call::<T>::declare {
payload: payload.clone(),
signature: signature.clone(),
})
.into()
});
match result {
Some((_, Ok(_))) => Ok(()),
Some((_, Err(_))) => Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::FailedToDeclareAffidavit.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
)),
None => Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::CannotSubmitAffidavitTx.into(),
block,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
)),
}
}
fn on_ran_service(&self) {
<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::DeclarAffidavitRoutineSuccess.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
);
}
}
impl<T: Config> RoutineOf<T::Public, BlockNumberFor<T>> for RotateAffidavitKey<T> {
fn who(at: &BlockNumberFor<T>) -> Result<T::Public, Self::Logger> {
let result = Finalized::<T, AffidavitId<T>, DeclareAffidavit<T>, Pallet<T>>::get(
NEXT_AFDT_KEY,
LOG_TARGET_AFDT,
None,
);
let afdt_key = match result {
Ok(Some(Confidence::Safe(key))) => key,
Ok(None) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Ok(Some(_)) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::info(
&Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
Err(_) => {
return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
};
let all_keys =
<<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
as RuntimeAppPublic>::all();
for key in all_keys {
let generic_pub:
<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
key.into();
let public: T::Public = generic_pub.into();
let account: AffidavitId<T> = public.clone().into_account().into();
if account == afdt_key {
return Ok(public);
}
}
Err(<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::ExpectedNextAffidavitKeyPairNotFound.into(),
*at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
))
}
}
impl<T: Config> Routines<BlockNumberFor<T>> for RotateAffidavitKey<T> {
fn can_run(&self) -> Result<(), Self::Logger> {
let current_session = CurrentSession::<T>::get();
let for_session = current_session.saturating_add(2);
let next_afdt_pub: AffidavitId<T> = self.by.clone().into_account().into();
if !AffidavitKeys::<T>::contains_key((for_session, next_afdt_pub)) {
let session_start = SessionStartAt::<T>::get();
let avg_session_len =
<<T as crate::Config>::NextSessionRotation as EstimateNextSessionRotation<
BlockNumberFor<T>,
>>::average_session_length();
let end_block = session_start.saturating_add(avg_session_len);
if self.at >= end_block {
Finalized::<T, AffidavitId<T>, DeclareAffidavit<T>, Pallet<T>>::remove(
NEXT_AFDT_KEY,
LOG_TARGET_AFDT,
None,
)
.map_err(|_| {
<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
)
})?;
Finalized::<T, AffidavitId<T>, InitAffidavitKey<T>, Pallet<T>>::remove(
ACTIVE_AFDT_KEY,
LOG_TARGET_AFDT,
None,
)
.map_err(|_| {
<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
)
})?;
return Err(<T as Logging<BlockNumberFor<T>>>::error(
&Error::<T>::ValidationStopped.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
return Err(<T as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::AffidavitTxAwaitingStatus.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
));
}
Ok(())
}
fn run_service(&self) -> Result<(), Self::Logger> {
Self::can_run(self)?;
Finalized::<T, AffidavitId<T>, DeclareAffidavit<T>, Pallet<T>>::remove(
NEXT_AFDT_KEY,
LOG_TARGET_AFDT,
None,
)
.map_err(|_| {
<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
)
})?;
Finalized::<T, AffidavitId<T>, InitAffidavitKey<T>, Pallet<T>>::mutate(
ACTIVE_AFDT_KEY,
|_| Ok(self.by.clone().into_account().into()),
LOG_TARGET_AFDT,
None,
)
.map_err(|_| {
<Self as Logging<BlockNumberFor<T>>>::warn(
&Error::<T>::OCWStorageDecisionHalt.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
)
})?;
Ok(())
}
fn on_ran_service(&self) {
<Self as Logging<BlockNumberFor<T>>>::debug(
&Error::<T>::RotateAffidavitKeyRoutineSuccess.into(),
self.at,
LOG_TARGET_AFDT,
Some(std_fmt::<T>),
);
}
}
impl<T: Config> ForksHandler<T, ForkLocalDepot> for Pallet<T> {
const TAG: &[u8] = b"pallet_chain_manager";
const MAX_FORKS: u32 = T::MAX_FORKS;
const MAX_RECOVER_TRAVERSAL: u32 = T::MAX_FORK_RECOVERY_TRAVERSAL;
fn max_forks_error() -> DispatchError {
Error::<T>::MaxOCWForksAttained.into()
}
fn forks_not_enabled() -> DispatchError {
Error::<T>::OCWForksNotEnabled.into()
}
fn inconsistent_forks() -> DispatchError {
Error::<T>::OCWForksInconsistent.into()
}
}
#[cfg(test)]
pub mod tests {
use crate::mock::*;
use codec::Encode;
use frame_benchmarking::account;
use frame_suite::routines::*;
use frame_support::{assert_err, assert_ok, traits::{EstimateNextSessionRotation}};
use sp_core::blake2_256;
use std::collections::BTreeMap;
#[test]
fn init_affidavit_key_can_run_return_err_affidavit_key_exists() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id).unwrap();
run_to_block(20);
let routine = InitAffidavitKey { at: 20 };
assert_err!(routine.can_run(), Error::AffidavitKeyExists);
})
}
#[test]
fn init_affidavit_key_can_run_return_err_active_afdt_key_not_yet_finalized() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id).unwrap();
run_to_block(10);
let routine = InitAffidavitKey { at: 10 };
assert_err!(routine.can_run(), Error::ActiveAfdtKeyNotYetFinalized);
})
}
#[test]
fn init_affidavit_key_can_run_return_ok_since_aff_key_dose_not_exists_in_keystore() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id: AffidavitId = account("dummy", 1, 1);
insert_active_afdt_key(aff_id).unwrap();
run_to_block(20);
let routine = InitAffidavitKey { at: 20 };
assert_ok!(routine.can_run());
})
}
#[test]
fn init_affidavit_key_run_service_returns_ok_since_affidavit_key_already_exists() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id).unwrap();
run_to_block(20);
let routine = InitAffidavitKey { at: 20 };
assert_ok!(routine.run_service());
})
}
#[test]
fn init_affidavit_key_run_service_returns_ok_after_successful_initialization() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let routine = InitAffidavitKey { at: 10 };
assert_ok!(routine.can_run());
let aff_key = get_afdt_key();
assert!(aff_key.is_none());
assert_eq!(affidavit_key_count(), 0);
assert_ok!(routine.run_service());
assert_err!(routine.can_run(), Error::ActiveAfdtKeyNotYetFinalized);
run_to_block(30);
assert_err!(routine.can_run(), Error::AffidavitKeyExists);
let aff_key = get_finalized_afdt_key();
assert!(aff_key.is_some());
assert_eq!(affidavit_key_count(), 1);
})
}
#[test]
fn try_election_can_run_returns_ok() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id.clone()).unwrap();
let pub_afdt = get_public_key(aff_id.clone()).unwrap();
run_to_block(300);
let election_routine = TryElection {
by: pub_afdt,
at: 300,
};
assert_ok!(election_routine.can_run());
})
}
#[test]
fn try_election_can_run_returns_err_not_affidavit_period() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id.clone()).unwrap();
let pub_afdt = get_public_key(aff_id.clone()).unwrap();
run_to_block(250);
let election_routine = TryElection {
by: pub_afdt,
at: 250,
};
assert_err!(election_routine.can_run(), Error::NotElectionPeriod);
})
}
#[test]
fn try_election_run_service_returns_ok_not_election_window() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id.clone()).unwrap();
let pub_afdt = get_public_key(aff_id.clone()).unwrap();
run_to_block(250);
let election_routine = TryElection {
by: pub_afdt,
at: 250,
};
assert_ok!(election_routine.run_service());
})
}
#[test]
fn try_election_run_service_returns_ok_for_duplicate_election_execution() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
CurrentSession::put(1);
SessionStartsAt::put(1);
init_fork_graph();
run_to_block(10);
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id.clone()).unwrap();
let pub_afdt = get_public_key(aff_id.clone()).unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let for_session = CurrentSession::get() + 2;
let afdt_key = get_afdt_key().unwrap();
AffidavitKeys::insert((for_session, afdt_key), ALICE);
let for_session = CurrentSession::get() + 1;
ElectsPreparedBy::insert(for_session, (ALICE, 310));
run_to_block(350);
let election_routine = TryElection {
by: pub_afdt,
at: 350,
};
assert_ok!(election_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
})
}
#[test]
fn try_election_run_service_returns_ok_when_extrinsic_submitted_succesfully() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
CurrentSession::put(1);
SessionStartsAt::put(1);
init_fork_graph();
run_to_block(10);
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id.clone()).unwrap();
let pub_afdt = get_public_key(aff_id.clone()).unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let for_session = CurrentSession::get() + 2;
let afdt_key = get_finalized_afdt_key().unwrap();
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(350);
let election_routine = TryElection {
by: pub_afdt,
at: 350,
};
let tx_len = env.pool_state.read().transactions.len();
assert_eq!(tx_len, 0);
assert_ok!(election_routine.run_service());
let tx_len = env.pool_state.read().transactions.len();
assert_eq!(tx_len, 1);
})
}
#[test]
fn declare_affidavit_who_returns_public_key() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key);
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
let who = DeclareAffidavit::who(&30).unwrap();
assert_eq!(who, pub_key);
})
}
#[test]
fn declare_affidavit_who_returns_err_expected_to_hold_active_affidavit_key() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let who = DeclareAffidavit::who(&10);
assert!(who.is_err());
assert_err!(who, Error::ExpectedToHoldActiveAffidavitKey);
})
}
#[test]
fn declare_affidavit_who_returns_err_active_afdt_key_not_yet_finalized() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
FinalityAfter::put(60_000);
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(15);
let who = DeclareAffidavit::who(&10);
assert!(who.is_err());
assert_err!(who, Error::ActiveAfdtKeyNotYetFinalized);
})
}
#[test]
fn declare_affidavit_who_returns_err_expected_active_affidavit_key_pair_not_found() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let aff_id: AffidavitId = account("dummy", 1, 1);
insert_active_afdt_key(aff_id).unwrap();
run_to_block(20);
let who = DeclareAffidavit::who(&10);
assert!(who.is_err());
assert_err!(who, Error::ExpectedActiveAffidavitKeyPairNotFound);
})
}
#[test]
fn declare_affidavit_can_run_returns_ok() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
assert_ok!(declare_routine.can_run());
})
}
#[test]
fn declate_affidavit_run_service_submits_the_extrinsic_and_returns_ok() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
SessionStartsAt::put(1);
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
assert_ok!(declare_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 1);
})
}
#[test]
fn rotate_affidavit_key_who_returns_public_key() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
assert_ok!(declare_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 1);
let rotate_afdt_key = get_finalized_next_afdt_key();
assert!(rotate_afdt_key.is_some());
let rotate_afdt_key = rotate_afdt_key.unwrap();
let rotate_pub_key = get_public_key(rotate_afdt_key).unwrap();
let rotate_at = aff_begin + 35;
let _rotate_routine = RotateAffidavitKey {
by: rotate_pub_key.clone(),
at: rotate_at,
};
run_to_block(rotate_at);
let actual_rotate_pub_key = RotateAffidavitKey::who(&rotate_at).unwrap();
assert_eq!(actual_rotate_pub_key, rotate_pub_key);
})
}
#[test]
fn rotate_affidavit_key_who_returns_err_expected_to_hold_finalized_next_afdt_key() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
let rotate_afdt_key = get_next_afdt_key();
assert!(rotate_afdt_key.is_some());
let rotate_afdt_key = rotate_afdt_key.unwrap();
let rotate_pub_key = get_public_key(rotate_afdt_key).unwrap();
let rotate_at = aff_begin + 10;
let _rotate_routine = RotateAffidavitKey {
by: rotate_pub_key.clone(),
at: rotate_at,
};
run_to_block(rotate_at);
assert_err!(
RotateAffidavitKey::who(&rotate_at),
Error::ExpectedToHoldFinalizedNextAffidavitKey
);
})
}
#[test]
fn rotate_affidavit_key_can_run_returns_ok() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
assert_ok!(declare_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 1);
let rotate_afdt_key = get_finalized_next_afdt_key();
assert!(rotate_afdt_key.is_some());
let rotate_afdt_key = rotate_afdt_key.unwrap();
let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
let rotate_at = aff_begin + 35;
let rotate_routine = RotateAffidavitKey {
by: rotate_pub_key.clone(),
at: rotate_at,
};
run_to_block(rotate_at);
let for_session = CurrentSession::get() + 2;
AffidavitKeys::insert((for_session, rotate_afdt_key), ALICE);
assert_ok!(rotate_routine.can_run());
})
}
#[test]
fn rotate_affidavit_key_can_run_returns_err_affidavit_tx_awaiting_status() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
assert_ok!(declare_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 1);
let rotate_afdt_key = get_finalized_next_afdt_key();
assert!(rotate_afdt_key.is_some());
let rotate_afdt_key = rotate_afdt_key.unwrap();
let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
let rotate_at = aff_begin + 35;
let rotate_routine = RotateAffidavitKey {
by: rotate_pub_key.clone(),
at: rotate_at,
};
run_to_block(rotate_at);
assert_err!(rotate_routine.can_run(), Error::AffidavitTxAwaitingStatus);
})
}
#[test]
fn rotate_affidavit_key_can_run_returns_err_validation_stopped_when_window_expired() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
assert_ok!(declare_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 1);
let rotate_afdt_key = get_finalized_next_afdt_key();
assert!(rotate_afdt_key.is_some());
let rotate_afdt_key = rotate_afdt_key.unwrap();
let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
let avg_session_len: BlockNumber = NextSessionRotation::average_session_length();
let rotate_at = avg_session_len + 10;
let rotate_routine = RotateAffidavitKey {
by: rotate_pub_key.clone(),
at: rotate_at,
};
run_to_block(rotate_at);
assert_err!(rotate_routine.can_run(), Error::ValidationStopped);
let aff_key = get_afdt_key();
assert!(aff_key.is_none());
let next_aff_key = get_next_afdt_key();
assert!(next_aff_key.is_none());
})
}
#[test]
fn rotate_affidavit_key_run_service_returns_ok() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
SessionStartsAt::put(1);
init_fork_graph();
let init_routine = InitAffidavitKey { at: 10 };
init_routine.run_service().unwrap();
run_to_block(30);
let afdt_key = get_finalized_afdt_key().unwrap();
let public_key = get_public_key(afdt_key.clone());
assert!(public_key.is_some());
let pub_key = public_key.unwrap();
set_default_user_balance_and_hold(ALICE).unwrap();
set_default_user_balance_and_hold(ALAN).unwrap();
enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
direct_fund_author(ALAN, ALICE, 500).unwrap();
let aff_window = compute_affidavit_window().unwrap();
let aff_begin = aff_window.start;
run_to_block(aff_begin);
AllowAffidavits::put(true);
let declare_routine = DeclareAffidavit {
by: pub_key,
at: aff_begin + 5,
};
run_to_block(aff_begin + 5);
assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
let for_session = CurrentSession::get() + 1;
AffidavitKeys::insert((for_session, afdt_key), ALICE);
run_to_block(aff_begin + 30);
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 0);
assert_ok!(declare_routine.run_service());
let txs_len = env.pool_state.read().transactions.len();
assert_eq!(txs_len, 1);
let rotate_afdt_key = get_finalized_next_afdt_key();
assert!(rotate_afdt_key.is_some());
let rotate_afdt_key = rotate_afdt_key.unwrap();
let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
let rotate_at = aff_begin + 35;
let rotate_routine = RotateAffidavitKey {
by: rotate_pub_key.clone(),
at: rotate_at,
};
run_to_block(rotate_at);
let for_session = CurrentSession::get() + 2;
AffidavitKeys::insert((for_session, rotate_afdt_key.clone()), ALICE);
assert_ok!(rotate_routine.run_service());
let next_afdt_key = get_next_afdt_key();
assert!(next_afdt_key.is_none());
let afdt_key = get_afdt_key();
assert!(afdt_key.is_some());
assert_eq!(afdt_key.unwrap(), rotate_afdt_key);
})
}
#[test]
fn finalized_insert_success() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let key = b"ACTIVE_KEY";
let value: AccountId = account("dummyid", 1, 1);
assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
let fork_aware_value = ForkAwareInitAfdtKey::get(key, None, None).unwrap();
assert!(fork_aware_value.is_some());
let value_hash = fork_aware_value.unwrap();
let persistent_value = PersistentInitAfdtKey::get(key, None, None).unwrap();
assert!(persistent_value.is_some());
let ledger = persistent_value.unwrap();
let observation = ledger.0.get(&value_hash).unwrap();
assert_eq!(observation.first_seen, 12000);
assert_eq!(observation.last_seen, 12000);
assert_eq!(observation.blocks_seen, 0);
assert_eq!(observation.value, value);
})
}
#[test]
fn finalized_get_success() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
let key = b"ACTIVE_KEY";
init_fork_graph();
let value: AccountId = account("dummyid", 1, 1);
assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
assert!(finalized_get.is_some());
let confidance_value = finalized_get.unwrap();
assert_eq!(confidance_value, Confidence::Unsafe(value.clone()));
run_to_block_with_finalized_key(12, key);
let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
assert!(finalized_get.is_some());
let confidance_value = finalized_get.unwrap();
assert_eq!(confidance_value, Confidence::Risky(value.clone()));
run_to_block_with_finalized_key(17, key);
let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
assert!(finalized_get.is_some());
let confidance_value = finalized_get.unwrap();
assert_eq!(confidance_value, Confidence::Safe(value));
})
}
#[test]
fn finalized_get_returns_err_due_to_hanging_value() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let key = b"ACTIVE_KEY";
let value: AccountId = account("dummyid", 1, 1);
let hash = blake2_256(&value.encode());
let value_hash = ValueHash::new(hash);
assert_ok!(ForkAwareInitAfdtKey::insert(key, &value_hash, None, None));
let finalized_get = FinalizedInitAfdtKey::get(key, None, None);
assert!(finalized_get.is_err());
let e = finalized_get.unwrap_err();
assert_eq!(e, Error::ActiveAfdtKeyFinalizedHangingValue.into());
let forkaware_lookup = ForkAwareInitAfdtKey::get(key, None, None).unwrap();
assert!(forkaware_lookup.is_none());
})
}
#[test]
fn finalized_get_returns_err_due_to_hanging_hash() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let key = b"ACTIVE_KEY";
let value: AccountId = account("dummyid", 1, 1);
let hash = blake2_256(&value.encode());
let value_hash = ValueHash::new(hash);
assert_ok!(ForkAwareInitAfdtKey::insert(key, &value_hash, None, None));
let other_value: AccountId = account("otherdummyid", 1, 1);
let other_hash = blake2_256(&other_value.encode());
let other_value_hash = ValueHash::new(other_hash);
let observation = Observation::<Test, AccountId> {
first_seen: 6000,
last_seen: 6000,
blocks_seen: 0,
value: other_value,
};
let mut map = BTreeMap::new();
map.insert(other_value_hash, observation);
let ledger = Ledger::<Test, AccountId>(map);
assert_ok!(PersistentInitAfdtKey::insert(
key,
&ledger,
None,
None
));
let finalized_get = FinalizedInitAfdtKey::get(key, None, None);
assert!(finalized_get.is_err());
let e = finalized_get.unwrap_err();
assert_eq!(e, Error::ActiveAfdtKeySpeculativeHangingHash.into());
let forkaware_lookup = ForkAwareInitAfdtKey::get(key, None, None).unwrap();
assert!(forkaware_lookup.is_none());
let persistent = PersistentInitAfdtKey::get(key, None, None).unwrap();
assert!(persistent.is_some());
})
}
#[test]
fn finalized_remove_success() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let key = b"ACTIVE_KEY";
let value: AccountId = account("dummyid", 1, 1);
assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
let finalized_inspect = FinalizedInitAfdtKey::get(key, None, None).unwrap();
assert!(finalized_inspect.is_some());
assert_ok!(FinalizedInitAfdtKey::remove(key, None, None));
let finalized_inspect = FinalizedInitAfdtKey::get(key, None, None).unwrap();
assert!(finalized_inspect.is_none());
})
}
#[test]
fn finalized_mutate_success() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let key = b"ACTIVE_KEY";
let value: AccountId = account("dummyid", 1, 1);
assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
let new_val: AccountId = account("newdummyid", 1, 1);
assert_ok!(FinalizedInitAfdtKey::mutate(
key,
|val| {
match val {
Ok(Some(_v)) => Ok(new_val.clone()),
Ok(None) => Ok(new_val.clone()),
Err(e) => Err(e),
}
},
None,
None
));
let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
let new_finalized_value = match finalized_get {
Some(new_val) => match new_val {
Confidence::Unsafe(id) => id,
_ => value,
},
None => value,
};
assert_eq!(new_finalized_value, new_val);
let persistent = PersistentInitAfdtKey::get(key, None, None).unwrap().unwrap();
let (_, obs) = persistent.0.iter().next().unwrap();
assert_eq!(obs.blocks_seen, 0);
assert_eq!(obs.value, new_val);
})
}
}
#[cfg(test)]
mod serial_tests {
use crate::mock::*;
use serial_test::serial;
use frame_suite::routines::*;
use frame_support::assert_ok;
#[serial]
#[test]
#[ignore = "relies on global logger; fails under parallel test execution"]
fn init_affidavit_key_on_ran_service() {
chain_manager_test_ext().execute_with(|| {
let logger = init_logger();
System::set_block_number(105);
let init_afdt_routine = InitAffidavitKey { at: 105 };
InitAffidavitKey::on_ran_service(&init_afdt_routine);
let record = logger.last().unwrap();
assert_eq!(record.target(), "AFFIDAVIT");
assert_eq!(record.level(), log::Level::Debug);
let expected_msg = format!(
"๐งฑ [105] ๐ [Debug] ๐ฏ [AFFIDAVIT] ๐งพ Module(9): InitAffidavitKeyRoutineSuccess"
);
let actual_msg = record.args().to_string();
assert_eq!(actual_msg, expected_msg);
})
}
#[serial]
#[test]
#[ignore = "relies on global logger; fails under parallel test execution"]
fn try_election_on_ran_service() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
let logger = init_logger();
System::set_block_number(105);
let by = generate_affidavit_keypair();
let try_election_routine = TryElection { by: by, at: 105 };
TryElection::on_ran_service(&try_election_routine);
let record = logger.last().unwrap();
assert_eq!(record.target(), "ELECTION");
assert_eq!(record.level(), log::Level::Debug);
let expected_msg =
format!("๐งฑ [105] ๐ [Debug] ๐ฏ [ELECTION] ๐งพ Module(9): TryElectionRoutineSuccess");
let actual_msg = record.args().to_string();
assert_eq!(actual_msg, expected_msg);
})
}
#[serial]
#[test]
#[ignore = "relies on global logger; fails under parallel test execution"]
fn declare_affidavit_on_ran_service() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
let logger = init_logger();
System::set_block_number(105);
let by = generate_affidavit_keypair();
let declare_afdt_routine = DeclareAffidavit { by, at: 105 };
DeclareAffidavit::on_ran_service(&declare_afdt_routine);
let record = logger.last().unwrap();
assert_eq!(record.target(), "AFFIDAVIT");
assert_eq!(record.level(), log::Level::Debug);
let expected_msg = format!(
"๐งฑ [105] ๐ [Debug] ๐ฏ [AFFIDAVIT] ๐งพ Module(9): DeclarAffidavitRoutineSuccess"
);
let actual_msg = record.args().to_string();
assert_eq!(actual_msg, expected_msg);
})
}
#[serial]
#[test]
#[ignore = "relies on global logger; fails under parallel test execution"]
fn rotate_affidavit_key_on_ran_service() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
let logger = init_logger();
System::set_block_number(105);
let by = generate_affidavit_keypair();
let rotate_afdt_routine = RotateAffidavitKey { by, at: 105 };
RotateAffidavitKey::on_ran_service(&rotate_afdt_routine);
let record = logger.last().unwrap();
assert_eq!(record.target(), "AFFIDAVIT");
assert_eq!(record.level(), log::Level::Debug);
let expected_msg = format!(
"๐งฑ [105] ๐ [Debug] ๐ฏ [AFFIDAVIT] ๐งพ Module(9): RotateAffidavitKeyRoutineSuccess"
);
let actual_msg = record.args().to_string();
assert_eq!(actual_msg, expected_msg);
})
}
#[serial]
#[test]
#[ignore = "relies on global logger; fails under parallel test execution"]
fn try_election_run_service_returns_ok_when_active_afdt_key_is_not_declared_yet() {
let mut env = new_ocw_env();
env.ext.execute_with(|| {
init_fork_graph();
let log_record = init_logger();
let aff_id = generate_affidavit_id();
insert_active_afdt_key(aff_id.clone()).unwrap();
let pub_afdt = get_public_key(aff_id.clone()).unwrap();
run_to_block(300);
let election_routine = TryElection {
by: pub_afdt,
at: 300,
};
assert_ok!(election_routine.run_service());
let last_log = log_record.last().unwrap();
assert_eq!(last_log.level(), log::Level::Debug);
assert!(last_log
.args()
.to_string()
.contains("AffidavitKeyForDeclaration"));
assert_eq!(last_log.target(), "ELECTION");
})
}
}