use parity_wasm::elements;
#[derive(Clone)]
pub enum GasMeter {
External {
module: &'static str,
function: &'static str,
},
Internal {
global: &'static str,
func_instructions: elements::Instructions,
cost: u64,
},
}
use super::Rules;
pub trait Backend {
fn gas_meter<R: Rules>(self, module: &elements::Module, rules: &R) -> GasMeter;
}
pub mod host_function {
use super::{Backend, GasMeter, Rules};
use parity_wasm::elements::Module;
pub struct Injector {
module: &'static str,
name: &'static str,
}
impl Injector {
pub fn new(module: &'static str, name: &'static str) -> Self {
Self { module, name }
}
}
impl Backend for Injector {
fn gas_meter<R: Rules>(self, _module: &Module, _rules: &R) -> GasMeter {
GasMeter::External { module: self.module, function: self.name }
}
}
}
pub mod mutable_global {
use super::{Backend, GasMeter, Rules};
use alloc::vec;
use parity_wasm::elements::{self, Instruction, Module};
pub struct Injector {
pub global_name: &'static str,
}
impl Injector {
pub fn new(global_name: &'static str) -> Self {
Self { global_name }
}
}
impl Backend for Injector {
fn gas_meter<R: Rules>(self, module: &Module, rules: &R) -> GasMeter {
let gas_global_idx = module.globals_space() as u32;
let func_instructions = vec![
Instruction::GetGlobal(gas_global_idx),
Instruction::GetLocal(0),
Instruction::I64GeU,
Instruction::If(elements::BlockType::NoResult),
Instruction::GetGlobal(gas_global_idx),
Instruction::GetLocal(0),
Instruction::I64Sub,
Instruction::SetGlobal(gas_global_idx),
Instruction::Else,
Instruction::I64Const(-1i64), Instruction::SetGlobal(gas_global_idx), Instruction::Unreachable, Instruction::End,
Instruction::End,
];
let mut gas_fn_cost = func_instructions.iter().fold(0, |cost, instruction| {
cost + (rules.instruction_cost(instruction).unwrap_or(0) as u64)
});
let fail_cost = vec![
Instruction::I64Const(-1i64), Instruction::SetGlobal(gas_global_idx), Instruction::Unreachable, ]
.iter()
.fold(0, |cost, instruction| {
cost + (rules.instruction_cost(instruction).unwrap_or(0) as u64)
});
gas_fn_cost -= fail_cost;
GasMeter::Internal {
global: self.global_name,
func_instructions: elements::Instructions::new(func_instructions),
cost: gas_fn_cost,
}
}
}
}