1use std::io::Cursor;
20
21use darkfi_sdk::{
22 crypto::{
23 pasta_prelude::*,
24 smt::{PoseidonFp, SparseMerkleTree, StorageAdapter, EMPTY_NODES_FP, SMT_FP_DEPTH},
25 },
26 error::{ContractError, ContractResult},
27 wasm,
28};
29use darkfi_serial::{deserialize, serialize, Decodable, Encodable};
30use halo2_proofs::pasta::pallas;
31use log::{debug, error};
32use num_bigint::BigUint;
33use wasmer::{FunctionEnvMut, WasmPtr};
34
35use super::acl::acl_allow;
36use crate::runtime::vm_runtime::{ContractSection, Env};
37
38pub struct SledStorage<'a> {
40 overlay: &'a mut sled_overlay::SledDbOverlay,
41 tree_key: &'a [u8],
42}
43
44impl StorageAdapter for SledStorage<'_> {
45 type Value = pallas::Base;
46
47 fn put(&mut self, key: BigUint, value: pallas::Base) -> ContractResult {
48 if let Err(e) = self.overlay.insert(self.tree_key, &key.to_bytes_le(), &value.to_repr()) {
49 error!(
50 target: "runtime::smt::SledStorage::put",
51 "[WASM] SledStorage::put(): inserting key {:?}, value {:?} into DB tree: {:?}: {}",
52 key, value, self.tree_key, e,
53 );
54 return Err(ContractError::SmtPutFailed)
55 }
56
57 Ok(())
58 }
59
60 fn get(&self, key: &BigUint) -> Option<pallas::Base> {
61 let value = match self.overlay.get(self.tree_key, &key.to_bytes_le()) {
62 Ok(v) => v,
63 Err(e) => {
64 error!(
65 target: "runtime::smt::SledStorage::get",
66 "[WASM] SledStorage::get(): Fetching key {:?} from DB tree: {:?}: {}",
67 key, self.tree_key, e,
68 );
69 return None
70 }
71 };
72
73 let value = value?;
74 let mut repr = [0; 32];
75 repr.copy_from_slice(&value);
76
77 pallas::Base::from_repr(repr).into()
78 }
79
80 fn del(&mut self, key: &BigUint) -> ContractResult {
81 if let Err(e) = self.overlay.remove(self.tree_key, &key.to_bytes_le()) {
82 error!(
83 target: "runtime::smt::SledStorage::del",
84 "[WASM] SledStorage::del(): Removing key {:?} from DB tree: {:?}: {}",
85 key, self.tree_key, e,
86 );
87 return Err(ContractError::SmtDelFailed)
88 }
89
90 Ok(())
91 }
92}
93
94pub(crate) fn sparse_merkle_insert_batch(
102 mut ctx: FunctionEnvMut<Env>,
103 ptr: WasmPtr<u8>,
104 len: u32,
105) -> i64 {
106 let (env, mut store) = ctx.data_and_store_mut();
107 let cid = env.contract_id;
108
109 if let Err(e) = acl_allow(env, &[ContractSection::Update]) {
111 error!(
112 target: "runtime::smt::sparse_merkle_insert_batch",
113 "[WASM] [{}] sparse_merkle_insert_batch(): Called in unauthorized section: {}", cid, e,
114 );
115 return darkfi_sdk::error::CALLER_ACCESS_DENIED
116 }
117
118 env.subtract_gas(&mut store, 1);
121
122 let memory_view = env.memory_view(&store);
123 let Ok(mem_slice) = ptr.slice(&memory_view, len) else {
124 error!(
125 target: "runtime::smt::sparse_merkle_insert_batch",
126 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to make slice from ptr", cid,
127 );
128 return darkfi_sdk::error::INTERNAL_ERROR
129 };
130
131 let mut buf = vec![0_u8; len as usize];
132 if let Err(e) = mem_slice.read_slice(&mut buf) {
133 error!(
134 target: "runtime::smt::sparse_merkle_insert_batch",
135 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to read from memory slice: {}", cid, e,
136 );
137 return darkfi_sdk::error::INTERNAL_ERROR
138 };
139
140 let mut buf_reader = Cursor::new(buf);
145 let db_info_index: u32 = match Decodable::decode(&mut buf_reader) {
146 Ok(v) => v,
147 Err(e) => {
148 error!(
149 target: "runtime::smt::sparse_merkle_insert_batch",
150 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to decode db_info DbHandle: {}", cid, e,
151 );
152 return darkfi_sdk::error::INTERNAL_ERROR
153 }
154 };
155 let db_info_index = db_info_index as usize;
156
157 let db_smt_index: u32 = match Decodable::decode(&mut buf_reader) {
158 Ok(v) => v,
159 Err(e) => {
160 error!(
161 target: "runtime::smt::sparse_merkle_insert_batch",
162 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to decode db_smt DbHandle: {}", cid, e,
163 );
164 return darkfi_sdk::error::INTERNAL_ERROR
165 }
166 };
167 let db_smt_index = db_smt_index as usize;
168
169 let db_roots_index: u32 = match Decodable::decode(&mut buf_reader) {
170 Ok(v) => v,
171 Err(e) => {
172 error!(
173 target: "runtime::smt::sparse_merkle_insert_batch",
174 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to decode db_roots DbHandle: {}", cid, e,
175 );
176 return darkfi_sdk::error::INTERNAL_ERROR
177 }
178 };
179 let db_roots_index = db_roots_index as usize;
180
181 let db_handles = env.db_handles.borrow();
182 let n_dbs = db_handles.len();
183
184 if n_dbs <= db_info_index || n_dbs <= db_smt_index || n_dbs <= db_roots_index {
185 error!(
186 target: "runtime::smt::sparse_merkle_insert_batch",
187 "[WASM] [{}] sparse_merkle_insert_batch(): Requested DbHandle that is out of bounds", cid,
188 );
189 return darkfi_sdk::error::INTERNAL_ERROR
190 }
191 let db_info = &db_handles[db_info_index];
192 let db_smt = &db_handles[db_smt_index];
193 let db_roots = &db_handles[db_roots_index];
194
195 if db_info.contract_id != env.contract_id ||
197 db_smt.contract_id != env.contract_id ||
198 db_roots.contract_id != env.contract_id
199 {
200 error!(
201 target: "runtime::smt::sparse_merkle_insert_batch",
202 "[WASM] [{}] sparse_merkle_insert_batch(): Unauthorized to write to DbHandle", cid,
203 );
204 return darkfi_sdk::error::CALLER_ACCESS_DENIED
205 }
206
207 let root_key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
209 Ok(v) => v,
210 Err(e) => {
211 error!(
212 target: "runtime::smt::sparse_merkle_insert_batch",
213 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to decode key vec: {}", cid, e,
214 );
215 return darkfi_sdk::error::INTERNAL_ERROR
216 }
217 };
218
219 let nullifiers: Vec<pallas::Base> = match Decodable::decode(&mut buf_reader) {
221 Ok(v) => v,
222 Err(e) => {
223 error!(
224 target: "runtime::smt::sparse_merkle_insert_batch",
225 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to decode pallas::Base: {}", cid, e,
226 );
227 return darkfi_sdk::error::INTERNAL_ERROR
228 }
229 };
230
231 if buf_reader.position() != (len as u64) {
233 error!(
234 target: "runtime::smt::sparse_merkle_insert_batch",
235 "[WASM] [{}] sparse_merkle_insert_batch(): Mismatch between given length, and cursor length", cid,
236 );
237 return darkfi_sdk::error::INTERNAL_ERROR
238 }
239
240 let hasher = PoseidonFp::new();
242 let lock = env.blockchain.lock().unwrap();
243 let mut overlay = lock.overlay.lock().unwrap();
244 let smt_store = SledStorage { overlay: &mut overlay, tree_key: &db_smt.tree };
245 let mut smt = SparseMerkleTree::<
246 SMT_FP_DEPTH,
247 { SMT_FP_DEPTH + 1 },
248 pallas::Base,
249 PoseidonFp,
250 SledStorage,
251 >::new(smt_store, hasher, &EMPTY_NODES_FP);
252
253 let inserted_nullifiers = nullifiers.len() * 32;
255
256 let leaves: Vec<_> = nullifiers.iter().map(|x| (*x, *x)).collect();
258 if let Err(e) = smt.insert_batch(leaves) {
259 error!(
260 target: "runtime::smt::sparse_merkle_insert_batch",
261 "[WASM] [{}] sparse_merkle_insert_batch(): SMT failed to insert batch: {}", cid, e,
262 );
263 return darkfi_sdk::error::INTERNAL_ERROR
264 };
265
266 let latest_root = smt.root();
269
270 let latest_root_data = serialize(&latest_root);
272 if latest_root_data.len() != 32 {
273 error!(
274 target: "runtime::smt::sparse_merkle_insert_batch",
275 "[WASM] [{}] sparse_merkle_insert_batch(): Latest root data length missmatch: {}", cid, latest_root_data.len(),
276 );
277 return darkfi_sdk::error::INTERNAL_ERROR
278 }
279
280 let mut new_value_data = Vec::with_capacity(32 + 1);
282 if let Err(e) = env.tx_hash.inner().encode(&mut new_value_data) {
283 error!(
284 target: "runtime::smt::sparse_merkle_insert_batch",
285 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to serialize transaction hash: {}", cid, e,
286 );
287 return darkfi_sdk::error::INTERNAL_ERROR
288 };
289 if let Err(e) = env.call_idx.encode(&mut new_value_data) {
290 error!(
291 target: "runtime::smt::sparse_merkle_insert_batch",
292 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to serialize call index: {}", cid, e,
293 );
294 return darkfi_sdk::error::INTERNAL_ERROR
295 };
296 if new_value_data.len() != 32 + 1 {
297 error!(
298 target: "runtime::smt::sparse_merkle_insert_batch",
299 "[WASM] [{}] sparse_merkle_insert_batch(): New value data length missmatch: {}", cid, new_value_data.len(),
300 );
301 return darkfi_sdk::error::INTERNAL_ERROR
302 }
303
304 let root_value_data_set = match overlay.get(&db_roots.tree, &latest_root_data) {
306 Ok(data) => data,
307 Err(e) => {
308 error!(
309 target: "runtime::smt::sparse_merkle_insert_batch",
310 "[WASM] [{}] sparse_merkle_insert_batch(): SMT failed to retrieve current root snapshot: {}", cid, e,
311 );
312 return darkfi_sdk::error::INTERNAL_ERROR
313 }
314 };
315
316 let root_value_data_set = match root_value_data_set {
319 Some(value_data_set) => {
320 let mut value_data_set: Vec<Vec<u8>> = match deserialize(&value_data_set) {
321 Ok(set) => set,
322 Err(e) => {
323 error!(
324 target: "runtime::smt::sparse_merkle_insert_batch",
325 "[WASM] [{}] sparse_merkle_insert_batch(): Failed to deserialize current root snapshot: {}", cid, e,
326 );
327 return darkfi_sdk::error::INTERNAL_ERROR
328 }
329 };
330
331 if !value_data_set.contains(&new_value_data) {
332 value_data_set.push(new_value_data);
333 }
334
335 value_data_set
336 }
337 None => vec![new_value_data],
338 };
339
340 debug!(
342 target: "runtime::smt::sparse_merkle_insert_batch",
343 "[WASM] [{}] sparse_merkle_insert_batch(): Appending SMT root to db: {:?}", cid, latest_root,
344 );
345 if overlay.insert(&db_roots.tree, &latest_root_data, &serialize(&root_value_data_set)).is_err()
346 {
347 error!(
348 target: "runtime::smt::sparse_merkle_insert_batch",
349 "[WASM] [{}] sparse_merkle_insert_batch(): Couldn't insert to db_roots tree", cid,
350 );
351 return darkfi_sdk::error::INTERNAL_ERROR
352 }
353
354 debug!(
356 target: "runtime::smt::sparse_merkle_insert_batch",
357 "[WASM] [{}] sparse_merkle_insert_batch(): Replacing latest SMT root pointer", cid,
358 );
359 if overlay.insert(&db_info.tree, &root_key, &latest_root_data).is_err() {
360 error!(
361 target: "runtime::smt::sparse_merkle_insert_batch",
362 "[WASM] [{}] sparse_merkle_insert_batch(): Couldn't insert latest root to db_info tree", cid,
363 );
364 return darkfi_sdk::error::INTERNAL_ERROR
365 }
366
367 drop(overlay);
371 drop(lock);
372 drop(db_handles);
373 env.subtract_gas(&mut store, inserted_nullifiers as u64);
374
375 wasm::entrypoint::SUCCESS
376}