darkfi/runtime/import/db/
db_get.rs1use darkfi_serial::Decodable;
20use tracing::{debug, error};
21use wasmer::{FunctionEnvMut, WasmPtr};
22
23use crate::runtime::{
24 import::{acl::acl_allow, util::wasm_mem_read},
25 vm_runtime::{ContractSection, Env},
26};
27
28pub(crate) fn db_get(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
38 db_get_internal(ctx, ptr, ptr_len, false)
39}
40
41pub(crate) fn db_get_local(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
51 db_get_internal(ctx, ptr, ptr_len, true)
52}
53
54pub(crate) fn db_get_internal(
61 mut ctx: FunctionEnvMut<Env>,
62 ptr: WasmPtr<u8>,
63 ptr_len: u32,
64 local: bool,
65) -> i64 {
66 let lt = if local { "db_get_local" } else { "db_get" };
67 let (env, mut store) = ctx.data_and_store_mut();
68 let cid = env.contract_id;
69
70 if let Err(e) =
72 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
73 {
74 error!(
75 target: "runtime::db::{lt}",
76 "[WASM] [{cid}] {lt}(): Called in unauthorized section: {e}",
77 );
78 return darkfi_sdk::error::CALLER_ACCESS_DENIED
79 }
80
81 env.subtract_gas(&mut store, 1);
83
84 let mut buf_reader = match wasm_mem_read(env, &store, ptr, ptr_len) {
86 Ok(v) => v,
87 Err(e) => {
88 error!(
89 target: "runtime::db::{lt}",
90 "[WASM] [{cid}] {lt}(): Failed to read wasm memory: {e}",
91 );
92 return darkfi_sdk::error::DB_GET_FAILED
93 }
94 };
95
96 let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
98 Ok(v) => v,
99 Err(e) => {
100 error!(
101 target: "runtime::db::{lt}",
102 "[WASM] [{cid}] {lt}(): Failed to decode DbHandle: {e}",
103 );
104 return darkfi_sdk::error::DB_GET_FAILED
105 }
106 };
107
108 let db_handle_index = db_handle_index as usize;
109
110 let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
112 Ok(v) => v,
113 Err(e) => {
114 error!(
115 target: "runtime::db::db_get",
116 "[WASM] [{cid}] db_get(): Failed to decode key from vec: {e}",
117 );
118 return darkfi_sdk::error::DB_GET_FAILED
119 }
120 };
121
122 if buf_reader.position() != ptr_len as u64 {
124 error!(
125 target: "runtime::db::{lt}",
126 "[WASM] [{cid}] {lt}(): Trailing bytes in argument stream",
127 );
128 return darkfi_sdk::error::DB_GET_FAILED
129 }
130
131 let db_handles = if local { env.local_db_handles.borrow() } else { env.db_handles.borrow() };
133
134 if db_handles.len() <= db_handle_index {
136 error!(
137 target: "runtime::db::{lt}",
138 "[WASM] [{cid}] {lt}(): Requested DbHandle that is out of bounds",
139 );
140 return darkfi_sdk::error::DB_GET_FAILED
141 }
142
143 let db_handle = &db_handles[db_handle_index];
145
146 let ret: Option<Vec<u8>> = if local {
148 let db = env.tx_local.lock();
150 let Some(db_cid) = db.get(&db_handle.contract_id) else {
151 error!(
152 target: "runtime::db::{lt}",
153 "[WASM] [{cid}] {lt}(): Could not find db for {}",
154 db_handle.contract_id,
155 );
156 return darkfi_sdk::error::DB_GET_FAILED
157 };
158
159 let Some(tree) = db_cid.get(&db_handle.tree) else {
160 error!(
161 target: "runtime::db::{lt}",
162 "[WASM] [{cid}] {lt}(): Could not find db tree for {}",
163 db_handle.contract_id,
164 );
165 return darkfi_sdk::error::DB_GET_FAILED
166 };
167
168 tree.get(&key).cloned()
169 } else {
170 match env.blockchain.lock().unwrap().overlay.lock().unwrap().get(&db_handle.tree, &key) {
171 Ok(v) => v.map(|iv| iv.to_vec()),
172 Err(e) => {
173 error!(
174 target: "runtime::db::{lt}",
175 "[WASM] [{cid}] {lt}(): Internal error getting from tree: {e}",
176 );
177 return darkfi_sdk::error::DB_GET_FAILED
178 }
179 }
180 };
181 drop(db_handles);
182
183 let Some(return_data) = ret else {
185 debug!(
186 target: "runtime::db::{lt}",
187 "[WASM] [{cid}] {lt}(): Return data is empty",
188 );
189 return darkfi_sdk::error::DB_GET_EMPTY
190 };
191
192 if return_data.len() > u32::MAX as usize {
193 return darkfi_sdk::error::DATA_TOO_LARGE
194 }
195
196 env.subtract_gas(&mut store, return_data.len() as u64);
198
199 let mut objects = env.objects.borrow_mut();
201 if objects.len() == u32::MAX as usize {
202 return darkfi_sdk::error::DATA_TOO_LARGE
203 }
204
205 objects.push(return_data.to_vec());
208 (objects.len() - 1) as i64
209}