calimero_node_primitives/sync/
storage_bridge.rs1use std::cell::RefCell;
31use std::rc::Rc;
32
33use calimero_primitives::context::ContextId;
34use calimero_primitives::identity::PublicKey;
35use calimero_storage::env::RuntimeEnv;
36use calimero_storage::store::Key;
37use calimero_store::{key, types, Store};
38use tracing::warn;
39
40pub fn create_runtime_env(
61 store: &Store,
62 context_id: ContextId,
63 executor_id: PublicKey,
64) -> RuntimeEnv {
65 let callbacks = create_storage_callbacks(store, context_id);
66 RuntimeEnv::new(
67 callbacks.read,
68 callbacks.write,
69 callbacks.remove,
70 *context_id.as_ref(),
71 *executor_id.as_ref(),
72 )
73}
74
75#[expect(
80 clippy::type_complexity,
81 reason = "Matches RuntimeEnv callback signatures"
82)]
83struct StorageCallbacks {
84 read: Rc<dyn Fn(&Key) -> Option<Vec<u8>>>,
85 write: Rc<dyn Fn(Key, &[u8]) -> bool>,
86 remove: Rc<dyn Fn(&Key) -> bool>,
87}
88
89#[expect(
94 clippy::type_complexity,
95 reason = "Matches RuntimeEnv callback signatures"
96)]
97fn create_storage_callbacks(store: &Store, context_id: ContextId) -> StorageCallbacks {
98 let read: Rc<dyn Fn(&Key) -> Option<Vec<u8>>> = {
99 let handle = store.handle();
100 let ctx_id = context_id;
101 Rc::new(move |key: &Key| {
102 let storage_key = key.to_bytes();
103 let state_key = key::ContextState::new(ctx_id, storage_key);
104 match handle.get(&state_key) {
105 Ok(Some(state)) => Some(state.value.into_boxed().into_vec()),
106 Ok(None) => None,
107 Err(e) => {
108 warn!(
109 %ctx_id,
110 storage_key = %hex::encode(storage_key),
111 error = ?e,
112 "Storage read failed"
113 );
114 None
115 }
116 }
117 })
118 };
119
120 let write: Rc<dyn Fn(Key, &[u8]) -> bool> = {
121 let handle_cell: Rc<RefCell<_>> = Rc::new(RefCell::new(store.handle()));
122 let ctx_id = context_id;
123 Rc::new(move |key: Key, value: &[u8]| {
124 let storage_key = key.to_bytes();
125 let state_key = key::ContextState::new(ctx_id, storage_key);
126 let slice: calimero_store::slice::Slice<'_> = value.to_vec().into();
127 let state_value = types::ContextState::from(slice);
128 handle_cell
129 .borrow_mut()
130 .put(&state_key, &state_value)
131 .is_ok()
132 })
133 };
134
135 let remove: Rc<dyn Fn(&Key) -> bool> = {
136 let handle_cell: Rc<RefCell<_>> = Rc::new(RefCell::new(store.handle()));
137 let ctx_id = context_id;
138 Rc::new(move |key: &Key| {
139 let storage_key = key.to_bytes();
140 let state_key = key::ContextState::new(ctx_id, storage_key);
141 handle_cell.borrow_mut().delete(&state_key).is_ok()
142 })
143 };
144
145 StorageCallbacks {
146 read,
147 write,
148 remove,
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use std::sync::Arc;
155
156 use super::*;
157 use calimero_storage::env::with_runtime_env;
158 use calimero_storage::index::Index;
159 use calimero_storage::store::MainStorage;
160 use calimero_store::db::InMemoryDB;
161
162 #[test]
163 fn test_create_runtime_env_with_inmemory() {
164 let db = InMemoryDB::owned();
166 let store = Store::new(Arc::new(db));
167
168 let context_id = ContextId::from([1u8; 32]);
170 let identity = PublicKey::from([2u8; 32]);
171
172 let env = create_runtime_env(&store, context_id, identity);
174
175 let result = with_runtime_env(env, || {
177 Index::<MainStorage>::get_index(calimero_storage::address::Id::root())
179 });
180
181 assert!(result.is_ok());
183 }
184}