From 8c63257a11c4d8115c104c678de3cfa4af49d2b8 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 27 Mar 2023 10:28:22 +0200 Subject: [PATCH] Add Cache::save_wasm_unchecked --- CHANGELOG.md | 8 ++++++ packages/vm/src/cache.rs | 55 ++++++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e588c6ccbc..9b95cf4e85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-vm: Add `Cache::save_wasm_unchecked` to save Wasm blobs that have + been checked before. This is useful for state-sync where we know the Wasm code + was checked when it was first uploaded. ([#1635]) + +[#1635]: https://github.com/CosmWasm/cosmwasm/pull/1635 + ### Changed - cosmwasm-vm: Add checks for table section of Wasm blob ([#1631]). diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index 3984e5e114..46a64e5e80 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -159,8 +159,27 @@ where } } + /// Takes a Wasm bytecode and stores it to the cache. + /// + /// This performs static checks, compiles the bytescode to a module and + /// stores the Wasm file on disk. + /// + /// This does the same as [`save_wasm_unchecked`] plus the static checks. + /// When a Wasm blob is stored the first time, use this function. pub fn save_wasm(&self, wasm: &[u8]) -> VmResult { check_wasm(wasm, &self.available_capabilities)?; + self.save_wasm_unchecked(wasm) + } + + /// Takes a Wasm bytecode and stores it to the cache. + /// + /// This compiles the bytescode to a module and + /// stores the Wasm file on disk. + /// + /// This does the same as [`save_wasm`] but without the static checks. + /// When a Wasm blob is stored which was previously checked (e.g. as part of state sync), + /// use this function. + pub fn save_wasm_unchecked(&self, wasm: &[u8]) -> VmResult { let module = compile(wasm, None, &[])?; let mut cache = self.inner.lock().unwrap(); @@ -431,6 +450,14 @@ mod tests { static CONTRACT: &[u8] = include_bytes!("../testdata/hackatom.wasm"); static IBC_CONTRACT: &[u8] = include_bytes!("../testdata/ibc_reflect.wasm"); + // Invalid because it doesn't contain required memory and exports + static INVALID_CONTRACT_WAT: &str = r#"(module + (type $t0 (func (param i32) (result i32))) + (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32) + get_local $p0 + i32.const 1 + i32.add)) + "#; fn default_capabilities() -> HashSet { capabilities_from_csv("iterator,staking") @@ -489,17 +516,7 @@ mod tests { #[test] fn save_wasm_rejects_invalid_contract() { - // Invalid because it doesn't contain required memory and exports - let wasm = wat::parse_str( - r#"(module - (type $t0 (func (param i32) (result i32))) - (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32) - get_local $p0 - i32.const 1 - i32.add)) - "#, - ) - .unwrap(); + let wasm = wat::parse_str(INVALID_CONTRACT_WAT).unwrap(); let cache: Cache = unsafe { Cache::new(make_testing_options()).unwrap() }; @@ -530,6 +547,22 @@ mod tests { assert_eq!(cache.stats().misses, 0); } + #[test] + fn save_wasm_unchecked_works() { + let cache: Cache = + unsafe { Cache::new(make_testing_options()).unwrap() }; + cache.save_wasm_unchecked(CONTRACT).unwrap(); + } + + #[test] + fn save_wasm_unchecked_accepts_invalid_contract() { + let wasm = wat::parse_str(INVALID_CONTRACT_WAT).unwrap(); + + let cache: Cache = + unsafe { Cache::new(make_testing_options()).unwrap() }; + cache.save_wasm_unchecked(&wasm).unwrap(); + } + #[test] fn load_wasm_works() { let cache: Cache =