jam-tooling 0.1.26

Various helpful utilities for JAM tooling developers
Documentation
use crate::{CodeInfo, Error};
use codec::{Compact, Decode};
use futures::StreamExt;
use jam_program_blob_common::{ConventionalMetadata as Metadata, CrateInfo};
use jam_std_common::{Node, NodeError, NodeExt as _, Service, SyncStatus};
use jam_types::{HeaderHash, ServiceId};
use std::future::Future;

pub trait NodeExt: Node {
	fn query_service(
		&self,
		head: HeaderHash,
		id: ServiceId,
	) -> impl Future<Output = Result<(Service, CodeInfo<CrateInfo>), anyhow::Error>> + Send {
		async move {
			use CodeInfo::*;
			let info = self.service_data(head, id).await?.ok_or(Error::ServiceNotFound)?;
			let maybe_code = self.service_preimage(head, id, info.code_hash.0).await?;
			let meta = match maybe_code {
				None => CodeNotProvided(info.code_hash.0),
				Some(code) =>
					match <(Compact<u32>, Metadata)>::decode(&mut &code[..]).ok().map(|x| x.1) {
						None => Undefined(info.code_hash.0),
						Some(Metadata::Info(crate_info)) => Known(crate_info),
					},
			};
			Ok((info, meta))
		}
	}

	fn wait_for_sync(&self) -> impl Future<Output = Result<(), anyhow::Error>> + Send {
		async move {
			let mut sync_state = self.subscribe_sync_status().await?;
			loop {
				let status = sync_state.next().await;
				match status {
					Some(Ok(SyncStatus::Completed)) => break,
					Some(Ok(_)) => continue,
					Some(Err(e)) => return Err(e.into()),
					None => break,
				}
			}
			// Wait for any non-genesis block to be finalized
			let mut final_block = self.subscribe_finalized_block().await?;
			loop {
				let status = final_block.next().await;
				match status {
					Some(Ok(block)) if block.slot > 0 => {
						match self.parent(block.header_hash).await {
							Ok(parent) => {
								if parent.slot > 0 {
									// Break only if the parent of the finalized block is
									// non-genesis.
									break;
								}
								eprintln!("Waiting for two non-genesis blocks to be finalized...");
							},
							Err(NodeError::BlockUnavailable(_)) => {
								// Just wait for another block
								eprintln!("Waiting for two non-genesis blocks to be finalized and available...");
							},
							Err(err) => return Err(err.into()),
						}
					},
					Some(Ok(_)) => {
						eprintln!("Waiting for two non-genesis blocks to be finalized...");
					},
					Some(Err(e)) => return Err(e.into()),
					None => break,
				}
			}
			Ok(())
		}
	}
}

impl<T: Node + ?Sized> NodeExt for T {}