use crate::{indexer::*, *}; use futures::join; use std::collections::BTreeMap; pub async fn monitor_expirations( data: &Data, blocks: u32, _sessions: u32, ) -> Result<(), subxt::Error> { let client = data.client(); let indexer = data.indexer.clone(); let parent_hash = client .storage() .at_latest() .await? .fetch(&runtime::storage().system().parent_hash()) .await? .unwrap(); let addr_current_block = runtime::storage().system().number(); let addr_current_session = runtime::storage().session().current_index(); let (current_block, _current_session) = join!( client.storage().at(parent_hash).fetch(&addr_current_block), client .storage() .at(parent_hash) .fetch(&addr_current_session) ); let current_block = current_block?.unwrap_or_default(); let end_block = current_block + blocks; let mut identity_cache = IdentityCache::new(client.clone(), indexer); // Certifications let mut basic_certs_iter = client .storage() .at(parent_hash) .iter(runtime::storage().certification().certs_removable_on_iter()) .await?; let mut basic_certs = BTreeMap::new(); while let Some(Ok(item)) = basic_certs_iter.next().await { let block_number = BlockNumber::from_le_bytes(item.key_bytes[40..44].try_into().unwrap()); if block_number < end_block { basic_certs.insert(block_number - current_block, item.value); } } for (title, certs) in [("Certifications", basic_certs)] { println!("\n{title}:"); for (blocks_left, certs) in certs { println!("{blocks_left} blocks before expiration:"); for (issuer_id, receiver_id) in certs { println!( " {} ({}) -> {} ({})", identity_cache .fetch_identity(issuer_id,) .await .unwrap_or_else(|_| "?".into()), issuer_id, identity_cache .fetch_identity(receiver_id,) .await .unwrap_or_else(|_| "?".into()), receiver_id, ); } } } // Memberships let mut basic_membership_iter = client .storage() .at_latest() .await? .iter(runtime::storage().membership().memberships_expire_on_iter()) .await?; let mut basic_memberships = BTreeMap::new(); while let Some(Ok(item)) = basic_membership_iter.next().await { let block_number = BlockNumber::from_le_bytes(item.key_bytes[40..44].try_into().unwrap()); if block_number < end_block { if block_number < current_block { dbg!((block_number, current_block)); } basic_memberships.insert(block_number - current_block, item.value); } } for (title, memberships) in [("Memberships", basic_memberships)] { println!("\n{title}:"); for (blocks_left, membership) in memberships { println!("{blocks_left} blocks before expiration:"); for identity_id in membership { println!( " {} ({})", identity_cache .fetch_identity(identity_id) .await .unwrap_or_else(|_| "?".into()), identity_id, ); } } } Ok(()) } use std::collections::{hash_map, HashMap}; pub struct IdentityCache { client: Client, identities: HashMap<IdtyId, String>, indexer: Option<Indexer>, } impl IdentityCache { pub fn new(client: Client, indexer: Option<Indexer>) -> Self { Self { client, identities: HashMap::new(), indexer, } } pub async fn fetch_identity(&mut self, identity_id: IdtyId) -> Result<String, GcliError> { Ok(match self.identities.entry(identity_id) { hash_map::Entry::Occupied(entry) => entry.get().clone(), hash_map::Entry::Vacant(entry) => entry .insert({ let pubkey = self .client .storage() .at_latest() .await? .fetch(&runtime::storage().identity().identities(identity_id)) .await? .ok_or_else(|| anyhow!("Identity {} not found", identity_id))? .owner_key .to_string(); format!( "“ {} ”", if let Some(indexer) = &self.indexer { if let Some(username) = indexer.username_by_pubkey(&pubkey).await { username } else { pubkey } } else { pubkey } ) }) .clone(), }) } }