diff --git a/Cargo.lock b/Cargo.lock index 49591b6d59..ab6558fe85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -385,6 +385,7 @@ dependencies = [ "clru", "cosmwasm-crypto", "cosmwasm-std", + "crc32fast", "criterion", "enumset", "hex", @@ -397,6 +398,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.3", + "target-lexicon", "tempfile", "thiserror", "wasmer", diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index 4cd374d42d..d7f1a815fd 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -36,6 +36,7 @@ bench = false [dependencies] clru = "0.4.0" +crc32fast = "1.3.2" # Uses the path when built locally; uses the given version from crates.io when published cosmwasm-std = { path = "../std", version = "1.2.4", default-features = false } cosmwasm-crypto = { path = "../crypto", version = "1.2.4" } @@ -70,6 +71,7 @@ wat = "1.0" clap = "2.33.3" rand = "0.8" leb128 = "0.2" +target-lexicon = "0.12" [[bench]] name = "main" diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs index a0729f3a23..bcf13b737c 100644 --- a/packages/vm/src/modules/file_system_cache.rs +++ b/packages/vm/src/modules/file_system_cache.rs @@ -1,10 +1,11 @@ use std::fs; +use std::hash::Hash; use std::io; use std::path::Path; use std::path::PathBuf; use thiserror::Error; -use wasmer::{DeserializeError, Module, Store}; +use wasmer::{DeserializeError, Module, Store, Target}; use crate::checksum::Checksum; use crate::errors::{VmError, VmResult}; @@ -186,6 +187,17 @@ fn estimate_module_size(module_path: &Path) -> VmResult { Ok(module_size) } +/// Creates an identifier for the Wasmer `Target` that is used for +/// cache invalidation. The output is reasonable human friendly to be useable +/// in file path component. +fn target_id(target: &Target) -> String { + // Use a custom Hasher implementation to avoid randomization. + let mut deterministic_hasher = crc32fast::Hasher::new(); + target.hash(&mut deterministic_hasher); + let hash = deterministic_hasher.finalize(); + format!("{}-{:08X}", target.triple(), hash) // print 4 byte hash as 8 hex characters +} + #[cfg(test)] mod tests { use std::fs; @@ -295,4 +307,28 @@ mod tests { let existed = cache.remove(&checksum).unwrap(); assert!(!existed); } + + #[test] + fn target_id_works() { + let triple = wasmer::Triple { + architecture: wasmer::Architecture::X86_64, + vendor: target_lexicon::Vendor::Nintendo, + operating_system: target_lexicon::OperatingSystem::Fuchsia, + environment: target_lexicon::Environment::Gnu, + binary_format: target_lexicon::BinaryFormat::Coff, + }; + let target = Target::new(triple.clone(), wasmer::CpuFeature::POPCNT.into()); + let id = target_id(&target); + assert_eq!(id, "x86_64-nintendo-fuchsia-gnu-coff-4721E3F4"); + // Changing CPU features changes the hash part + let target = Target::new(triple, wasmer::CpuFeature::AVX512DQ.into()); + let id = target_id(&target); + assert_eq!(id, "x86_64-nintendo-fuchsia-gnu-coff-D5C8034F"); + + // Works for durrect target (hashing is deterministic); + let target = Target::default(); + let id1 = target_id(&target); + let id2 = target_id(&target); + assert_eq!(id1, id2); + } }