gear_common/
program_storage.rs1use gear_core::pages::{WasmPage, numerated::tree::IntervalsTree};
20
21use super::*;
22use crate::storage::{MapStorage, TripleMapStorage};
23use core::fmt::Debug;
24
25pub trait Error {
29 fn duplicate_item() -> Self;
31
32 fn program_not_found() -> Self;
34
35 fn not_active_program() -> Self;
37
38 fn cannot_find_page_data() -> Self;
40
41 fn program_code_not_found() -> Self;
43}
44
45pub type MemoryMap = BTreeMap<GearPage, PageBuf>;
46
47pub trait ProgramStorage {
49 type InternalError: Error;
50 type Error: From<Self::InternalError> + Debug;
51 type BlockNumber: Copy + Saturating;
52 type AccountId: Eq + PartialEq;
53
54 type ProgramMap: MapStorage<Key = ActorId, Value = Program<Self::BlockNumber>>;
55 type MemoryPageMap: TripleMapStorage<Key1 = ActorId, Key2 = MemoryInfix, Key3 = GearPage, Value = PageBuf>;
56 type AllocationsMap: MapStorage<Key = ActorId, Value = IntervalsTree<WasmPage>>;
57
58 fn reset() {
60 Self::ProgramMap::clear();
61 Self::MemoryPageMap::clear();
62 Self::AllocationsMap::clear();
63 }
64
65 fn add_program(
67 program_id: ActorId,
68 program: ActiveProgram<Self::BlockNumber>,
69 ) -> Result<(), Self::Error> {
70 Self::ProgramMap::mutate(program_id, |maybe| {
71 if maybe.is_some() {
72 return Err(Self::InternalError::duplicate_item().into());
73 }
74
75 *maybe = Some(Program::Active(program));
76 Ok(())
77 })
78 }
79
80 fn get_program(program_id: ActorId) -> Option<Program<Self::BlockNumber>> {
82 Self::ProgramMap::get(&program_id)
83 }
84
85 fn program_exists(program_id: ActorId) -> bool {
87 Self::ProgramMap::contains_key(&program_id)
88 }
89
90 fn update_active_program<F, ReturnType>(
92 program_id: ActorId,
93 update_action: F,
94 ) -> Result<ReturnType, Self::Error>
95 where
96 F: FnOnce(&mut ActiveProgram<Self::BlockNumber>) -> ReturnType,
97 {
98 Self::update_program_if_active(program_id, |program, _bn| match program {
99 Program::Active(active_program) => update_action(active_program),
100 _ => unreachable!("invariant kept by update_program_if_active"),
101 })
102 }
103
104 fn remove_data_for_pages(
105 program_id: ActorId,
106 memory_infix: MemoryInfix,
107 pages: impl Iterator<Item = GearPage>,
108 ) {
109 for page in pages {
110 Self::remove_program_page_data(program_id, memory_infix, page);
111 }
112 }
113
114 fn allocations(program_id: ActorId) -> Option<IntervalsTree<WasmPage>> {
115 Self::AllocationsMap::get(&program_id)
116 }
117
118 fn set_allocations(program_id: ActorId, allocations: IntervalsTree<WasmPage>) {
119 Self::update_active_program(program_id, |program| {
120 program.allocations_tree_len = u32::try_from(allocations.intervals_amount())
121 .unwrap_or_else(|err| {
122 unreachable!("allocations tree length is too big to fit into u32: {err}")
124 });
125 })
126 .unwrap_or_else(|err| {
127 unreachable!("Failed to update program allocations: {err:?}")
129 });
130 Self::AllocationsMap::insert(program_id, allocations);
131 }
132
133 fn clear_allocations(program_id: ActorId) {
134 Self::AllocationsMap::remove(program_id);
135 }
136
137 fn memory_infix(program_id: ActorId) -> Option<MemoryInfix> {
138 match Self::ProgramMap::get(&program_id) {
139 Some(Program::Active(program)) => Some(program.memory_infix),
140 _ => None,
141 }
142 }
143
144 fn update_program_if_active<F, ReturnType>(
147 program_id: ActorId,
148 update_action: F,
149 ) -> Result<ReturnType, Self::Error>
150 where
151 F: FnOnce(&mut Program<Self::BlockNumber>, Self::BlockNumber) -> ReturnType,
152 {
153 let mut program =
154 Self::ProgramMap::get(&program_id).ok_or(Self::InternalError::program_not_found())?;
155 let bn = match program {
156 Program::Active(ref p) => p.expiration_block,
157 _ => return Err(Self::InternalError::not_active_program().into()),
158 };
159
160 let result = update_action(&mut program, bn);
161 Self::ProgramMap::insert(program_id, program);
162
163 Ok(result)
164 }
165
166 fn get_program_pages_data(
168 program_id: ActorId,
169 memory_infix: MemoryInfix,
170 ) -> Result<MemoryMap, Self::Error> {
171 Ok(Self::MemoryPageMap::iter_prefix(&program_id, &memory_infix).collect())
172 }
173
174 fn set_program_page_data(
176 program_id: ActorId,
177 memory_infix: MemoryInfix,
178 page: GearPage,
179 page_buf: PageBuf,
180 ) {
181 Self::MemoryPageMap::insert(program_id, memory_infix, page, page_buf);
182 }
183
184 fn remove_program_page_data(
186 program_id: ActorId,
187 memory_infix: MemoryInfix,
188 page_num: GearPage,
189 ) {
190 Self::MemoryPageMap::remove(program_id, memory_infix, page_num);
191 }
192
193 fn clear_program_memory(program_id: ActorId, memory_infix: MemoryInfix) {
195 Self::MemoryPageMap::clear_prefix(program_id, memory_infix);
196 }
197
198 fn pages_final_prefix() -> [u8; 32];
200}