zingen/wasm/
host.rs
1use crate::{Error, Result};
4use anyhow::anyhow;
5use core::str::FromStr;
6use opcodes::{Cancun as OpCode, OpCode as _};
7
8#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
10pub enum HostFunc {
11 Evm(OpCode),
13 NoOp,
15 EmitABI,
19 U256MAX,
21 Revert(usize),
23 Label(CompilerLabel),
25}
26
27impl HostFunc {
28 pub fn stack_in(&self) -> u8 {
30 match self {
31 Self::Evm(op) => op.stack_in() as u8,
32 _ => 0,
33 }
34 }
35
36 pub fn stack_out(&self) -> u8 {
38 match self {
39 Self::Evm(op) => op.stack_out() as u8,
40 _ => 0,
41 }
42 }
43}
44
45impl TryFrom<(&str, &str)> for HostFunc {
46 type Error = Error;
47
48 fn try_from(import: (&str, &str)) -> Result<Self> {
49 let (module, name) = import;
50 match import {
51 ("zinkc", name) => match name {
52 "emit_abi" => Ok(Self::EmitABI),
53 "u256_add" => Ok(Self::Evm(OpCode::ADD)),
54 "u256_sub" => Ok(Self::Evm(OpCode::SUB)),
55 "u256_lt" => Ok(Self::Evm(OpCode::LT)),
56 "u256_max" => Ok(Self::U256MAX),
57 "u256_addmod" => Ok(Self::Evm(OpCode::ADDMOD)),
58 "u256_mulmod" => Ok(Self::Evm(OpCode::MULMOD)),
59 "label_reserve_mem_32" => Ok(Self::Label(CompilerLabel::ReserveMemory32)),
60 "label_reserve_mem_64" => Ok(Self::Label(CompilerLabel::ReserveMemory64)),
61 _ => Err(Error::HostFuncNotFound(module.into(), name.into())),
62 },
63 ("evm", name) => Ok(Self::Evm(OpCode::from_str(name).map_err(|_| {
64 tracing::error!("Failed to load host function: {:?}", import);
65 Error::HostFuncNotFound(module.into(), name.into())
66 })?)),
67 ("asm", name) => match name {
68 n if n.starts_with("sload") => Ok(Self::Evm(OpCode::SLOAD)),
69 n if n.starts_with("tload") => Ok(Self::Evm(OpCode::TLOAD)),
70 n if n.starts_with("revert") => {
71 let count = n.trim_start_matches("revert");
72 Ok(Self::Revert(count.parse().map_err(|e| anyhow!("{e}"))?))
73 }
74 n if n.starts_with("mulmod") => Ok(Self::Evm(OpCode::MULMOD)),
75 n if n.starts_with("addmod") => Ok(Self::Evm(OpCode::ADDMOD)),
76 _ => Ok(Self::NoOp),
77 },
78 ("bytes", instr) => match instr {
79 push if push.starts_with("push_bytes") => Ok(Self::NoOp),
80 sload if sload.starts_with("sload_bytes") => Ok(Self::Evm(OpCode::SLOAD)),
81 eq if eq.ends_with("_eq") => Ok(Self::Evm(OpCode::EQ)),
82 _ => {
83 tracing::warn!("Failed to load host function: {import:?} from module bytes");
84 Err(Error::HostFuncNotFound(module.into(), name.into()))
85 }
86 },
87 _ => {
88 tracing::warn!("Failed to load host function: {:?}", import);
89 Err(Error::HostFuncNotFound(module.into(), name.into()))
90 }
91 }
92 }
93}
94
95#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
97pub enum CompilerLabel {
98 ReserveMemory32,
99 ReserveMemory64,
100}
101
102#[cfg(test)]
103mod tests {
104 use anyhow::Ok;
105
106 use super::*;
107
108 #[test]
109 fn test_addmod_mulmod_host_functions() -> anyhow::Result<()> {
110 let addmod_func = HostFunc::try_from(("zinkc", "u256_addmod"))?;
111
112 assert_eq!(addmod_func, HostFunc::Evm(OpCode::ADDMOD));
113
114 let mulmod_func = HostFunc::try_from(("zinkc", "u256_mulmod"));
116 assert!(mulmod_func.is_ok());
117 Ok(())
118 }
119}