use std::{fs, io::Read, path::PathBuf};
use anyhow::{Context, Result};
use sp_core::H256;
use subxt::{contracts::*, ClientBuilder, DefaultNodeRuntime};
use crate::{crate_metadata, ExtrinsicOpts};
fn load_contract_code(path: Option<&PathBuf>) -> Result<Vec<u8>> {
let contract_wasm_path = match path {
Some(path) => path.clone(),
None => {
let metadata = crate_metadata::CrateMetadata::collect(&Default::default())?;
metadata.dest_wasm
}
};
log::info!("Contract code path: {}", contract_wasm_path.display());
let mut data = Vec::new();
let mut file = fs::File::open(&contract_wasm_path)
.context(format!("Failed to open {}", contract_wasm_path.display()))?;
file.read_to_end(&mut data)?;
Ok(data)
}
pub(crate) fn execute_deploy(
extrinsic_opts: &ExtrinsicOpts,
contract_wasm_path: Option<&PathBuf>,
) -> Result<H256> {
let code = load_contract_code(contract_wasm_path)?;
async_std::task::block_on(async move {
let cli = ClientBuilder::<DefaultNodeRuntime>::new()
.set_url(&extrinsic_opts.url.to_string())
.build()
.await?;
let signer = extrinsic_opts.signer()?;
let events = cli.put_code_and_watch(&signer, &code).await?;
let code_stored = events
.code_stored()?
.ok_or(anyhow::anyhow!("Failed to find CodeStored event"))?;
Ok(code_stored.code_hash)
})
}
#[cfg(test)]
mod tests {
use std::{fs, io::Write};
use crate::{cmd::deploy::execute_deploy, util::tests::with_tmp_dir, ExtrinsicOpts};
use assert_matches::assert_matches;
const CONTRACT: &str = r#"
(module
(func (export "call"))
(func (export "deploy"))
)
"#;
#[test]
#[ignore] fn deploy_contract() {
with_tmp_dir(|path| {
let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt");
let wasm_path = path.join("test.wasm");
let mut file = fs::File::create(&wasm_path).unwrap();
let _ = file.write_all(&wasm);
let url = url::Url::parse("ws://localhost:9944").unwrap();
let extrinsic_opts = ExtrinsicOpts {
url,
suri: "//Alice".into(),
password: None,
};
let result = execute_deploy(&extrinsic_opts, Some(&wasm_path));
assert_matches!(result, Ok(_));
Ok(())
})
}
}