use std::{collections::BTreeSet, ops::Deref};
use demo_custom::{InitMessage, WASM_BINARY};
use gclient::{EventListener, EventProcessor, GearApi, Result};
use gear_core::{ids::ActorId, pages::GearPage};
use parity_scale_codec::Encode;
async fn charge_10(
api: &GearApi,
program_id: ActorId,
listener: &mut EventListener,
) -> Result<String> {
let payload = b"10".to_vec();
let gas_info = api
.calculate_handle_gas(None, program_id, payload.clone(), 0, true)
.await?;
let (message_id, _hash) = api
.send_message_bytes(program_id, payload, gas_info.min_limit, 0)
.await?;
assert!(listener.message_processed(message_id).await?.succeed());
let msg = api.get_mailbox_messages(1).await.unwrap().pop();
if let Some(msg) = msg {
let message = api
.get_mailbox_message(msg.0.id())
.await
.unwrap()
.unwrap()
.0;
api.claim_value(msg.0.id()).await.unwrap();
return Ok(String::from_utf8(message.payload_bytes().to_vec()).unwrap());
}
Ok(String::new())
}
struct CleanupFolderOnDrop {
path: String,
}
impl Drop for CleanupFolderOnDrop {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.path).expect("Failed to cleanup after test")
}
}
#[tokio::test]
async fn memory_dump() -> Result<()> {
let api = GearApi::dev_from_path("../target/release/gear").await?;
let mut listener = api.subscribe().await?;
assert!(listener.blocks_running().await?);
let payload = InitMessage::Capacitor("15".to_string()).encode();
let gas_info = api
.calculate_upload_gas(None, WASM_BINARY.to_vec(), payload.clone(), 0, true)
.await?;
let (message_id, program_id, _hash) = api
.upload_program_bytes(
WASM_BINARY,
gclient::now_micros().to_le_bytes(),
payload,
gas_info.min_limit,
0,
)
.await?;
assert!(listener.message_processed(message_id).await?.succeed());
assert_eq!(
charge_10(&api, program_id, &mut listener).await.unwrap(),
""
);
let cleanup = CleanupFolderOnDrop {
path: "./296c6962726".to_string(),
};
api.save_program_memory_dump_at(program_id, None, "./296c6962726/demo_custom.dump")
.await
.unwrap();
assert_eq!(
charge_10(&api, program_id, &mut listener).await.unwrap(),
"Discharged: 20"
);
api.replace_program_memory(program_id, "./296c6962726/demo_custom.dump")
.await
.unwrap();
drop(cleanup);
assert_eq!(
charge_10(&api, program_id, &mut listener).await.unwrap(),
"Discharged: 20"
);
Ok(())
}
#[tokio::test]
async fn memory_download() -> Result<()> {
let api = GearApi::dev_from_path("../target/release/gear").await?;
let mut listener = api.subscribe().await?;
assert!(listener.blocks_running().await?);
let wat = r#"
(module
(import "env" "memory" (memory 512))
(export "init" (func $init))
(func $init
(local $counter i32)
(loop
(i32.store
(i32.mul (local.get $counter) (i32.const 0x8000))
(i32.const 0x42)
)
(i32.add (local.get $counter) (i32.const 1))
local.tee $counter
i32.const 1000
i32.lt_u
br_if 0
)
)
)
"#;
let wasm = wat::parse_str(wat).unwrap();
let (message_id, program_id, _hash) = api
.upload_program_bytes(
wasm,
gclient::now_micros().to_le_bytes(),
Vec::new(),
200_000_000_000,
0,
)
.await?;
assert!(listener.message_processed(message_id).await?.succeed());
let timer_start = gclient::now_micros();
let pages = api.get_program_pages_data_at(program_id, None).await?;
let timer_end = gclient::now_micros();
println!(
"Storage prefix iteration memory download took: {} ms",
(timer_end - timer_start) / 1000
);
let mut accessed_pages = BTreeSet::new();
let mut expected_data = [0u8; 0x4000];
expected_data[0] = 0x42;
for (page, data) in pages {
accessed_pages.insert(page);
assert_eq!(data.deref(), expected_data.as_slice());
}
assert_eq!(
accessed_pages,
(0..1000)
.map(|p| p * 2)
.map(Into::into)
.collect::<BTreeSet<GearPage>>()
);
let timer_start = gclient::now_micros();
let _pages = api
.get_program_specified_pages_data_at(program_id, accessed_pages.into_iter(), None)
.await?;
let timer_end = gclient::now_micros();
println!(
"Memory page by page download took: {} ms",
(timer_end - timer_start) / 1000
);
Ok(())
}