use std::path::Path;
use std::{fs::File, path::PathBuf};
use std::{io::prelude::*, str::FromStr};
use substrate_differ::differs::raw_differ::RawDiffer;
use substrate_differ::differs::raw_differ_options::RawDifferOptions;
use substrate_differ::differs::summary_differ::RuntimeSummaryDiffer;
use wasm_loader::{BlockRef, NodeEndpoint, OnchainBlock, Source};
use wasm_testbed::WasmTestBed;
mod chain_info;
mod chain_urls;
mod convert;
mod error;
mod macros;
mod metadata_wrapper;
mod runtime_info;
mod subwasm;
mod types;
pub use chain_info::*;
use log::{debug, info};
pub use runtime_info::*;
pub use subwasm::*;
pub use types::*;
pub fn print_magic_and_version(data: &[u8]) {
let is_substrate_wasm = WasmTestBed::is_substrate_wasm(&data.to_vec());
let version = WasmTestBed::get_metadata_version(data);
println!("✨ Magic number found: {}", if is_substrate_wasm { "YES" } else { "NO" });
println!("#️⃣ Extracted version : V{:?}", version);
}
fn get_node_url(chain: Option<&str>) -> Option<String> {
if let Some(chain) = chain {
let chain_info = ChainInfo::from_str(chain).expect("Unknown chain");
chain_info.get_random_url(None)
} else {
None
}
}
pub fn get_url(chain: Option<&str>, reference: &OnchainBlock) -> String {
let url = reference.endpoint.to_string();
let node_url = get_node_url(chain);
if let Some(chain_url) = node_url {
chain_url
} else {
url
}
}
pub fn get_source(chain: Option<&str>, source: Source, block_ref: Option<String>) -> Source {
let node_url = get_node_url(chain);
if let Some(chain_url) = node_url {
let endpoint = NodeEndpoint::from_str(&chain_url).unwrap();
Source::Chain(OnchainBlock { endpoint, block_ref })
} else {
source
}
}
pub fn download_runtime(url: &str, block_ref: Option<BlockRef>, output: Option<PathBuf>) -> color_eyre::Result<()> {
let url = match url {
url if url.starts_with("ws") => NodeEndpoint::WebSocket(url.to_string()),
url if url.starts_with("http") => NodeEndpoint::Http(url.to_string()),
_ => panic!("The url should either start with http or ws"),
};
let reference = OnchainBlock { endpoint: url, block_ref };
info!("Downloading runtime from {:?}", reference);
let loader =
wasm_loader::WasmLoader::load_from_source(&Source::Chain(reference)).expect("Getting wasm from the node");
let wasm = loader.bytes();
info!("Got the runtime, its size is {:?}", wasm.len());
let outfile = match output {
Some(path) => path,
_ => {
let mut i = 0;
let mut path;
loop {
path = format!("runtime_{:03?}.wasm", i);
i += 1;
assert!(i < 1000, "Ran out of indexes");
if !Path::new(&path).exists() {
break;
}
}
PathBuf::from(path)
}
};
info!("Saving runtime to {:?}", outfile);
let mut buffer = File::create(outfile)?;
buffer.write_all(wasm)?;
Ok(())
}
pub fn diff(src_a: Source, src_b: Source) {
debug!("Loading WASM runtimes:");
println!(" 🅰️ {:?}", src_a);
let runtime_a = WasmTestBed::new(&src_a).expect("Can only diff if the 2 runtimes can load");
println!(" 🅱️ {:?}", src_b);
let runtime_b = WasmTestBed::new(&src_b).expect("Can only diff if the 2 runtimes can load");
let runtime_diff = RuntimeSummaryDiffer::new(&runtime_a, &runtime_b);
runtime_diff.compare();
let metadiff = RawDiffer::new(runtime_a.metadata(), runtime_b.metadata());
metadiff.compare(RawDifferOptions::default());
}