1use std::{fs, io, path::Path};
7
8use alloy::primitives::B256;
9use wasmparser::BinaryReaderError;
10
11use crate::utils::wasm;
12
13pub const BROTLI_COMPRESSION_LEVEL: u32 = 11;
15
16pub const EOF_PREFIX_NO_DICT: &str = "EFF00000";
18
19pub const PROJECT_HASH_SECTION_NAME: &str = "project_hash";
22
23pub fn process_wasm_file(
25 filename: impl AsRef<Path>,
26 project_hash: [u8; 32],
27) -> Result<ProcessedWasm, ProcessWasmFileError> {
28 let wasm = fs::read(filename).map_err(ProcessWasmFileError::Read)?;
29 let wasm = wasm::remove_dangling_references(wasm)?;
30 let wasm = wasm::strip_user_metadata(wasm).map_err(ProcessWasmFileError::StripUserMetadata)?;
31 let wasm = wasm::add_custom_section(wasm, PROJECT_HASH_SECTION_NAME, project_hash)
32 .map_err(ProcessWasmFileError::AddProjectHash)?;
33 let wasm = wasmer::wat2wasm(&wasm)
34 .map_err(ProcessWasmFileError::Wat2Wasm)?
35 .to_vec();
36
37 let code = wasm::brotli_compress(wasm.as_slice(), BROTLI_COMPRESSION_LEVEL)
38 .map_err(ProcessWasmFileError::BrotliCompress)?;
39 let code = wasm::add_prefix(code, EOF_PREFIX_NO_DICT);
40
41 Ok(ProcessedWasm { wasm, code })
42}
43
44#[derive(Debug)]
45pub struct ProcessedWasm {
46 pub wasm: Vec<u8>,
47 pub code: Vec<u8>,
48}
49
50impl ProcessedWasm {
51 pub fn codehash(&self) -> B256 {
52 alloy::primitives::keccak256(&self.code)
53 }
54}
55
56#[derive(Debug, thiserror::Error)]
57pub enum ProcessWasmFileError {
58 #[error("error reading wasm file: {0}")]
59 Read(io::Error),
60 #[error("error removing dangling references: {0}")]
61 RemoveDanglingReferences(#[from] wasm::RemoveDanglingReferencesError),
62 #[error("error adding project hash to wasm file as a custom section: {0}")]
63 AddProjectHash(BinaryReaderError),
64 #[error("error stripping user metadata: {0}")]
65 StripUserMetadata(BinaryReaderError),
66 #[error("error converting Wat to Wasm: {0}")]
67 Wat2Wasm(wat::Error),
68 #[error("failed to compress Wasm bytes")]
69 BrotliCompress(io::Error),
70}