use crate::{code::InstrumentedCode, ids::ProgramId, pages::WasmPage};
use alloc::collections::BTreeSet;
use scale_info::scale::{Decode, Encode};
#[derive(Clone, Debug, Decode, Encode)]
pub struct Program {
id: ProgramId,
code: InstrumentedCode,
allocations: BTreeSet<WasmPage>,
is_initialized: bool,
}
impl Program {
pub fn new(id: ProgramId, code: InstrumentedCode) -> Self {
Program {
id,
code,
allocations: Default::default(),
is_initialized: false,
}
}
pub fn from_parts(
id: ProgramId,
code: InstrumentedCode,
allocations: BTreeSet<WasmPage>,
is_initialized: bool,
) -> Self {
Self {
id,
code,
allocations,
is_initialized,
}
}
pub fn code(&self) -> &InstrumentedCode {
&self.code
}
pub fn raw_code(&self) -> &[u8] {
self.code.code()
}
pub fn id(&self) -> ProgramId {
self.id
}
pub fn static_pages(&self) -> WasmPage {
self.code.static_pages()
}
pub fn is_initialized(&self) -> bool {
self.is_initialized
}
pub fn set_initialized(&mut self) {
self.is_initialized = true;
}
pub fn allocations(&self) -> &BTreeSet<WasmPage> {
&self.allocations
}
pub fn set_allocations(&mut self, allocations: BTreeSet<WasmPage>) {
self.allocations = allocations;
}
}
#[cfg(test)]
mod tests {
use super::Program;
use crate::{code::Code, ids::ProgramId};
use alloc::vec::Vec;
use gear_wasm_instrument::wasm_instrument::gas_metering::ConstantCostRules;
fn parse_wat(source: &str) -> Vec<u8> {
let module_bytes = wabt::Wat2Wasm::new()
.validate(false)
.convert(source)
.expect("failed to parse module")
.as_ref()
.to_vec();
module_bytes
}
#[test]
#[should_panic(expected = "Identifier must be 32 length")]
fn program_id_from_slice_error_implementation() {
let bytes = "foobar";
let _: ProgramId = bytes.as_bytes().into();
}
#[test]
fn program_memory() {
let wat = r#"
(module
(import "env" "gr_reply_to" (func $gr_reply_to (param i32)))
(import "env" "memory" (memory 2))
(export "handle" (func $handle))
(export "handle_reply" (func $handle))
(export "init" (func $init))
(func $handle
i32.const 65536
call $gr_reply_to
)
(func $handle_reply
i32.const 65536
call $gr_reply_to
)
(func $init)
)"#;
let binary: Vec<u8> = parse_wat(wat);
let code = Code::try_new(binary, 1, |_| ConstantCostRules::default(), None).unwrap();
let (code, _) = code.into_parts();
let program = Program::new(ProgramId::from(1), code);
assert_eq!(program.static_pages(), 2.into());
assert_eq!(program.allocations().len(), 0);
}
}