11diff --git a/crates/c_api/CMakeLists.txt b/crates/c_api/CMakeLists.txt
2- index b15c787a..54eaed2d 100644
2+ index b15c787..54eaed2 100644
33--- a/crates/c_api/CMakeLists.txt
44+++ b/crates/c_api/CMakeLists.txt
55@@ -6,6 +6,8 @@ option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
@@ -67,7 +67,7 @@ index b15c787a..54eaed2d 100644
6767- COMMENT "clang-format: Apply formatting rules for Wasmi C-API header files"
6868- )
6969diff --git a/crates/c_api/include/wasm.h b/crates/c_api/include/wasm.h
70- index 5ee617ff..5c79bde3 100644
70+ index 5ee617f..a76f10e 100644
7171--- a/crates/c_api/include/wasm.h
7272+++ b/crates/c_api/include/wasm.h
7373@@ -13,11 +13,17 @@
@@ -89,20 +89,22 @@ index 5ee617ff..5c79bde3 100644
8989 #endif
9090
9191 #ifdef __cplusplus
92- @@ -146,6 +152,11 @@ WASM_DECLARE_OWN(store)
92+ @@ -145,7 +151,13 @@ WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t
93+ WASM_DECLARE_OWN(store)
9394
9495 WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*);
95-
96+ + WASM_API_EXTERN own wasm_store_t* wasm_store_new_with_memory_max_pages(wasm_engine_t*, uint32_t max_pages);
97+ +
9698+ // Store fuel functions (forward declarations)
9799+ struct wasmi_error;
98- +
100+
99101+ WASM_API_EXTERN struct wasmi_error* wasm_store_get_fuel(const wasm_store_t*, uint64_t* fuel);
100102+ WASM_API_EXTERN struct wasmi_error* wasm_store_set_fuel(wasm_store_t*, uint64_t fuel);
101103
102104 ///////////////////////////////////////////////////////////////////////////////
103105 // Type Representations
104106diff --git a/crates/c_api/include/wasmi.h b/crates/c_api/include/wasmi.h
105- index 2caffa37..0c0584ec 100644
107+ index 2caffa3..0c0584e 100644
106108--- a/crates/c_api/include/wasmi.h
107109+++ b/crates/c_api/include/wasmi.h
108110@@ -10,7 +10,7 @@
@@ -128,18 +130,127 @@ index 2caffa37..0c0584ec 100644
128130
129131 #endif // WASMI_H
130132diff --git a/crates/c_api/src/store.rs b/crates/c_api/src/store.rs
131- index 56d4898f..543dbff8 100644
133+ index 56d4898..9abda8e 100644
132134--- a/crates/c_api/src/store.rs
133135+++ b/crates/c_api/src/store.rs
134- @@ -175,3 +175,44 @@ pub extern "C" fn wasmi_context_set_fuel(
136+ @@ -1,7 +1,7 @@
137+ use crate::{wasm_engine_t, wasmi_error_t, ForeignData};
138+ use alloc::{boxed::Box, sync::Arc};
139+ use core::{cell::UnsafeCell, ffi};
140+ - use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut};
141+ + use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut, StoreLimits, StoreLimitsBuilder};
142+
143+ /// This representation of a `Store` is used to implement the `wasm.h` API (and
144+ /// *not* the `wasmi.h` API!)
145+ @@ -16,7 +16,7 @@ use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut};
146+ /// least Wasmi's implementation).
147+ #[derive(Clone)]
148+ pub struct WasmStoreRef {
149+ - inner: Arc<UnsafeCell<Store<()>>>,
150+ + inner: Arc<UnsafeCell<Store<StoreLimits>>>,
151+ }
152+
153+ impl WasmStoreRef {
154+ @@ -27,7 +27,7 @@ impl WasmStoreRef {
155+ /// # Safety
156+ ///
157+ /// It is the callers responsibility to provide a valid `self`.
158+ - pub unsafe fn context(&self) -> StoreContext<'_, ()> {
159+ + pub unsafe fn context(&self) -> StoreContext<'_, StoreLimits> {
160+ (*self.inner.get()).as_context()
161+ }
162+
163+ @@ -38,7 +38,7 @@ impl WasmStoreRef {
164+ /// # Safety
165+ ///
166+ /// It is the callers responsibility to provide a valid `self`.
167+ - pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, ()> {
168+ + pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, StoreLimits> {
169+ (*self.inner.get()).as_context_mut()
170+ }
171+ }
172+ @@ -56,17 +56,71 @@ pub struct wasm_store_t {
173+
174+ wasmi_c_api_macros::declare_own!(wasm_store_t);
175+
176+ - /// Creates a new [`Store<()>`](wasmi::Store) for the given `engine`.
177+ + /// Creates a new [`Store<StoreLimits>`](wasmi::Store) for the given `engine`.
178+ + ///
179+ + /// The store is created with no resource limits (original behavior).
180+ + /// For memory-limited stores, use [`wasm_store_new_with_memory_max_pages`].
181+ ///
182+ /// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`].
183+ ///
184+ - /// Wraps [`<wasmi::Store<()>>::new`](wasmi::Store::new).
185+ + /// Wraps [`<wasmi::Store<StoreLimits>>::new`](wasmi::Store::new).
186+ #[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
187+ #[allow(clippy::arc_with_non_send_sync)]
188+ #[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
189+ pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
190+ let engine = &engine.inner;
191+ - let store = Store::new(engine, ());
192+ +
193+ + // Create store with no resource limits (original behavior)
194+ + let limits = StoreLimitsBuilder::new().build();
195+ + let store = Store::new(engine, limits);
196+ +
197+ + Box::new(wasm_store_t {
198+ + inner: WasmStoreRef {
199+ + inner: Arc::new(UnsafeCell::new(store)),
200+ + },
201+ + })
202+ + }
203+ +
204+ + /// Creates a new [`Store<StoreLimits>`](wasmi::Store) for the given `engine` with memory limits.
205+ + ///
206+ + /// This function creates a store with resource limits suitable for blockchain smart contracts.
207+ + /// The memory limit is enforced during WebAssembly execution.
208+ + ///
209+ + /// If `max_pages` exceeds 1024 (64MB), this function will panic.
210+ + ///
211+ + /// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`].
212+ + ///
213+ + /// Wraps [`<wasmi::Store<StoreLimits>>::new`](wasmi::Store::new).
214+ + #[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
215+ + #[allow(clippy::arc_with_non_send_sync)]
216+ + #[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
217+ + pub extern "C" fn wasm_store_new_with_memory_max_pages(
218+ + engine: &wasm_engine_t,
219+ + max_pages: u32,
220+ + ) -> Box<wasm_store_t> {
221+ + // Validate max_pages limit (64MB = 1024 pages)
222+ + if max_pages > 1024 {
223+ + panic!("max_pages ({}) exceeds maximum allowed value of 1024 pages (64MB)", max_pages);
224+ + }
225+ +
226+ + // Convert pages to bytes (each page is 64KB)
227+ + let max_memory_bytes = (max_pages as usize) * (64 * 1024);
228+ +
229+ + // Create store limits with blockchain-suitable defaults
230+ + let limits = StoreLimitsBuilder::new()
231+ + .memory_size(max_memory_bytes) // User-specified memory limit
232+ + .instances(1) // Single instance for blockchain
233+ + .tables(1) // Single table for blockchain
234+ + .memories(1) // Single memory for blockchain
235+ + .table_elements(64) // Limited table elements for blockchain
236+ + .trap_on_grow_failure(false) // Return -1 on growth failure instead of trapping
237+ + .build();
238+ +
239+ + let mut store = Store::new(&engine.inner, limits);
240+ +
241+ + // Install the resource limiter
242+ + store.limiter(|limits| limits);
243+ +
244+ Box::new(wasm_store_t {
245+ inner: WasmStoreRef {
246+ inner: Arc::new(UnsafeCell::new(store)),
247+ @@ -175,3 +229,40 @@ pub extern "C" fn wasmi_context_set_fuel(
135248 ) -> Option<Box<wasmi_error_t>> {
136249 crate::handle_result(store.set_fuel(fuel), |()| {})
137250 }
138251+
139252+ ////////////////////////////////////////////////////////////////////////////////////////
140253+ ////////////////////////////////////////////////////////////////////////////////////////
141- + ////////////////////////////////////////////////////////////////////////////////////////
142- + ////////////////////////////////////////////////////////////////////////////////////////
143254+
144255+ /// Returns the current fuel of the wasm store context in `fuel`.
145256+ ///
@@ -171,8 +282,6 @@ index 56d4898f..543dbff8 100644
171282+ store: &mut wasm_store_t,
172283+ fuel: u64,
173284+ ) -> Option<Box<wasmi_error_t>> {
174- +
175285+ let mut context = unsafe { store.inner.context_mut() };
176286+ crate::handle_result(context.set_fuel(fuel), |()| {})
177287+ }
178- +
0 commit comments