1pub mod cache;
7pub mod config;
8pub mod env;
9pub mod error;
10pub mod evm_api;
11pub mod evm_api_impl;
12#[allow(unused_mut)]
13pub mod host;
14pub mod ink;
15pub mod meter;
16pub mod middleware;
17pub mod native;
18pub mod pages;
19pub mod pricing;
20pub mod run;
21pub mod trace;
22
23pub use cache::InitCache;
24pub use config::{CompileConfig, StylusConfig};
25pub use evm_api::EvmApi;
26pub use evm_api_impl::StylusEvmApi;
27pub use ink::{Gas, Ink};
28pub use meter::{MachineMeter, MeteredMachine, STYLUS_ENTRY_POINT};
29pub use native::NativeInstance;
30pub use run::RunProgram;
31
32pub const STYLUS_DISCRIMINANT: [u8; 3] = [0xEF, 0xF0, 0x00];
38
39pub fn is_stylus_program(bytecode: &[u8]) -> bool {
43 bytecode.len() >= 4 && bytecode[..3] == STYLUS_DISCRIMINANT
44}
45
46pub fn strip_stylus_prefix(bytecode: &[u8]) -> Result<(&[u8], u8), &'static str> {
51 if bytecode.len() < 4 {
52 return Err("bytecode too short for Stylus prefix");
53 }
54 if bytecode[..3] != STYLUS_DISCRIMINANT {
55 return Err("bytecode does not have Stylus discriminant");
56 }
57 let version = bytecode[3];
58 Ok((&bytecode[4..], version))
59}
60
61pub const STYLUS_ROOT_DISCRIMINANT: [u8; 3] = [0xEF, 0xF0, 0x02];
63
64pub const STYLUS_FRAGMENT_DISCRIMINANT: [u8; 3] = [0xEF, 0xF0, 0x01];
66
67pub fn is_stylus_classic(bytecode: &[u8]) -> bool {
69 bytecode.len() > 3 && bytecode[..3] == STYLUS_DISCRIMINANT
70}
71
72pub fn is_stylus_root(bytecode: &[u8]) -> bool {
74 bytecode.len() > 3 && bytecode[..3] == STYLUS_ROOT_DISCRIMINANT
75}
76
77pub fn is_stylus_fragment(bytecode: &[u8]) -> bool {
79 bytecode.len() > 3 && bytecode[..3] == STYLUS_FRAGMENT_DISCRIMINANT
80}
81
82pub fn is_stylus_deployable(bytecode: &[u8], arbos_version: u64) -> bool {
84 use arb_chainspec::arbos_version as av;
85 if arbos_version < av::ARBOS_VERSION_STYLUS {
86 return false;
87 }
88 if arbos_version < av::ARBOS_VERSION_STYLUS_CONTRACT_LIMIT {
89 return is_stylus_classic(bytecode);
90 }
91 is_stylus_classic(bytecode) || is_stylus_root(bytecode)
92}
93
94pub fn decompress_wasm(bytecode: &[u8]) -> eyre::Result<Vec<u8>> {
98 if bytecode.len() < 4 || bytecode[..3] != STYLUS_DISCRIMINANT {
99 eyre::bail!("not a Stylus program");
100 }
101 let dict_byte = bytecode[3];
102 let compressed = &bytecode[4..];
103
104 let dict = match dict_byte {
105 0 => nitro_brotli::Dictionary::Empty,
106 1 => nitro_brotli::Dictionary::StylusProgram,
107 _ => eyre::bail!("unsupported dictionary type: {dict_byte}"),
108 };
109
110 nitro_brotli::decompress(compressed, dict)
111 .map_err(|e| eyre::eyre!("brotli decompression failed: {e:?}"))
112}
113
114pub fn activate_program(
119 wasm: &[u8],
120 codehash: &[u8; 32],
121 stylus_version: u16,
122 arbos_version: u64,
123 page_limit: u16,
124 debug: bool,
125 gas: &mut u64,
126) -> eyre::Result<arbos::programs::types::ActivationResult> {
127 let codehash_bytes32 = nitro_arbutil::Bytes32(*codehash);
128 let (_module, stylus_data) = nitro_prover::machine::Module::activate(
129 wasm,
130 &codehash_bytes32,
131 stylus_version,
132 arbos_version,
133 page_limit,
134 debug,
135 gas,
136 )?;
137
138 Ok(arbos::programs::types::ActivationResult {
139 module_hash: alloy_primitives::B256::from(_module.hash().0),
140 init_gas: stylus_data.init_cost,
141 cached_init_gas: stylus_data.cached_init_cost,
142 asm_estimate: stylus_data.asm_estimate,
143 footprint: stylus_data.footprint,
144 })
145}