diff --git a/live-tests/tests/sanity_gdev.rs b/live-tests/tests/sanity_gdev.rs index c25a3c6a89584bc9da3e5d83cfe6b243cc19c42c..6dbfe5b41700728b42bcfed30e444188a2912bc8 100644 --- a/live-tests/tests/sanity_gdev.rs +++ b/live-tests/tests/sanity_gdev.rs @@ -46,6 +46,11 @@ type IdtyValue = gdev_runtime::runtime_types::pallet_identity::types::IdtyValue<BlockNumber, AccountId32>; use gdev_runtime::runtime_types::pallet_identity::types::IdtyStatus; +struct Storage { + accounts: HashMap<AccountId32, AccountInfo>, + identities: HashMap<IdtyIndex, IdtyValue>, +} + #[tokio::test(flavor = "current_thread")] async fn main() -> anyhow::Result<()> { let ws_rpc_endpoint = @@ -87,6 +92,7 @@ async fn sanity_tests_at(client: Client, maybe_block_hash: Option<H256>) -> anyh account_id_bytes.copy_from_slice(&key.0[48..]); accounts.insert(AccountId32::new(account_id_bytes), account_info); } + println!("{} accounts.", accounts.len()); // Collect identities let mut identities = HashMap::new(); @@ -100,90 +106,138 @@ async fn sanity_tests_at(client: Client, maybe_block_hash: Option<H256>) -> anyh idty_index_bytes.copy_from_slice(&key.0[40..]); identities.insert(IdtyIndex::from_le_bytes(idty_index_bytes), idty_value); } + println!("{} identities.", identities.len()); - // ===== Verify storage ===== // + let storage = Storage { + accounts, + identities, + }; - verify_accounts(&accounts).await?; - verify_identities(&accounts, &identities).await?; + // ===== Verify storage ===== // - Ok(()) + verifier::Verifier::new().verify_storage(&storage).await } -async fn verify_accounts(accounts: &HashMap<AccountId32, AccountInfo>) -> anyhow::Result<()> { - for (account_id, account_info) in accounts { - if account_info.sufficients == 0 { - // Rule 1: If the account is not sufficient, it should have at least one provider - assert!( - account_info.providers > 0, - "Account {} has no providers nor sufficients", - account_id - ); - // Rule 2: If the account is not sufficient, it should comply to the existential deposit - assert!( - (account_info.data.free + account_info.data.reserved) >= 200, - "Account {} not respect existential deposit rule", - account_id - ); +mod verifier { + use super::*; + + pub(super) struct Verifier { + errors: Vec<String>, + } + + impl Verifier { + pub(super) fn new() -> Self { + Self { errors: Vec::new() } } - // Rule 3: If the account have consumers, it shoul have at least one provider - if account_info.consumers > 0 { - // Rule 1: If the account is not s - assert!( - account_info.providers > 0, - "Account {} has no providers nor sufficients", - account_id - ); + pub(super) async fn verify_storage(&mut self, storage: &Storage) -> anyhow::Result<()> { + self.verify_accounts(&storage.accounts).await?; + self.verify_identities(&storage.accounts, &storage.identities) + .await?; + + if self.errors.is_empty() { + Ok(()) + } else { + for error in &self.errors { + println!("{}", error); + } + Err(anyhow::anyhow!( + "Storage corrupted: {} errors.", + self.errors.len() + )) + } } - if account_id.as_slice() != TREASURY_ACCOUNT_ID { - // Rule 4: If the account is not a "special account", - // it should have a random id or a consumer - assert!( - account_info.data.random_id.is_some() || account_info.consumers > 0, - "Account {} has no random_id nor consumer", - account_id - ); + fn assert(&mut self, assertion: bool, error: String) { + if !assertion { + self.errors.push(error); + } } - } - Ok(()) -} -async fn verify_identities( - accounts: &HashMap<AccountId32, AccountInfo>, - identities: &HashMap<IdtyIndex, IdtyValue>, -) -> anyhow::Result<()> { - for (idty_index, idty_value) in identities { - // Rule 1: each identity should have an account - let idty_account = accounts - .get(&idty_value.owner_key) - .unwrap_or_else(|| panic!("Identity {} has no account", idty_index)); - - // Rule 2: each identity account should be sufficient - assert!( - idty_account.sufficients > 0, - "Identity {} is corrupted: idty_account.sufficients == 0", - idty_index - ); - - match idty_value.status { - IdtyStatus::Validated => { - // Rule 3: If the identity is validated, removable_on shoud be zero - assert!( - idty_value.removable_on == 0, - "Identity {} is corrupted: removable_on > 0 on validated idty", - idty_index - ); + async fn verify_accounts( + &mut self, + accounts: &HashMap<AccountId32, AccountInfo>, + ) -> anyhow::Result<()> { + for (account_id, account_info) in accounts { + if account_info.sufficients == 0 { + // Rule 1: If the account is not sufficient, it should have at least one provider + self.assert( + account_info.providers > 0, + format!("Account {} has no providers nor sufficients", account_id), + ); + // Rule 2: If the account is not sufficient, it should comply to the existential deposit + self.assert( + (account_info.data.free + account_info.data.reserved) >= 200, + format!( + "Account {} not respect existential deposit rule", + account_id + ), + ); + } + + // Rule 3: If the account have consumers, it shoul have at least one provider + if account_info.consumers > 0 { + // Rule 1: If the account is not s + self.assert( + account_info.providers > 0, + format!("Account {} has no providers nor sufficients", account_id), + ); + } + + if account_id.as_slice() != TREASURY_ACCOUNT_ID { + // Rule 4: If the account is not a "special account", + // it should have a random id or a consumer + self.assert( + account_info.data.random_id.is_some() || account_info.consumers > 0, + format!("Account {} has no random_id nor consumer", account_id), + ); + } } - _ => { - // Rule 4: If the identity is not validated, next_creatable_identity_on shoud be zero - assert!( - idty_value.next_creatable_identity_on == 0, - "Identity {} is corrupted: next_creatable_identity_on > 0 on non-validated idty", - idty_index + Ok(()) + } + + async fn verify_identities( + &mut self, + accounts: &HashMap<AccountId32, AccountInfo>, + identities: &HashMap<IdtyIndex, IdtyValue>, + ) -> anyhow::Result<()> { + for (idty_index, idty_value) in identities { + // Rule 1: each identity should have an account + let idty_account = accounts + .get(&idty_value.owner_key) + .unwrap_or_else(|| panic!("Identity {} has no account", idty_index)); + + // Rule 2: each identity account should be sufficient + self.assert( + idty_account.sufficients > 0, + format!( + "Identity {} is corrupted: idty_account.sufficients == 0", + idty_index + ), ); + + match idty_value.status { + IdtyStatus::Validated => { + // Rule 3: If the identity is validated, removable_on shoud be zero + self.assert( + idty_value.removable_on == 0, + format!( + "Identity {} is corrupted: removable_on > 0 on validated idty", + idty_index + ), + ); + } + _ => { + // Rule 4: If the identity is not validated, next_creatable_identity_on shoud be zero + self.assert( + idty_value.next_creatable_identity_on == 0, + format!("Identity {} is corrupted: next_creatable_identity_on > 0 on non-validated idty", + idty_index) + ); + } + } } + Ok(()) } } - Ok(()) }