clone_cw_multi_test/wasm_emulation/query/
wasm.rs1use std::marker::PhantomData;
2
3use crate::addons::MockApiBech32;
4use crate::prefixed_storage::get_full_contract_storage_namespace;
5use crate::queries::wasm::WasmRemoteQuerier;
6use crate::wasm_emulation::query::gas::{
7 GAS_COST_ALL_QUERIES, GAS_COST_CONTRACT_INFO, GAS_COST_RAW_COSMWASM_QUERY,
8};
9use crate::wasm_emulation::query::mock_querier::QueryResultWithGas;
10use crate::wasm_emulation::query::MockQuerier;
11use crate::Contract;
12
13use crate::wasm_emulation::contract::WasmContract;
14use cosmwasm_std::testing::MockStorage;
15use cosmwasm_vm::GasInfo;
16
17use cosmwasm_std::{
18 to_json_binary, Addr, ContractInfoResponse, CustomMsg, CustomQuery, OwnedDeps, Storage,
19 SystemError, SystemResult,
20};
21use cosmwasm_std::{ContractInfo, ContractResult};
22
23use cosmwasm_std::WasmQuery;
24use cw_orch::daemon::queriers::CosmWasm;
25use serde::de::DeserializeOwned;
26
27use crate::wasm_emulation::channel::RemoteChannel;
28
29use super::mock_querier::ForkState;
30
31pub struct WasmQuerier<
32 ExecC: CustomMsg + DeserializeOwned + 'static,
33 QueryC: CustomQuery + DeserializeOwned + 'static,
34> {
35 fork_state: ForkState<ExecC, QueryC>,
36}
37
38impl<
39 ExecC: CustomMsg + DeserializeOwned + 'static,
40 QueryC: CustomQuery + DeserializeOwned + 'static,
41 > WasmQuerier<ExecC, QueryC>
42{
43 pub fn new(fork_state: ForkState<ExecC, QueryC>) -> Self {
44 Self { fork_state }
45 }
46
47 pub fn query(&self, remote: RemoteChannel, request: &WasmQuery) -> QueryResultWithGas {
48 match request {
49 WasmQuery::ContractInfo { contract_addr } => {
50 let addr = Addr::unchecked(contract_addr);
51 let data = if let Some(local_contract) = self
52 .fork_state
53 .querier_storage
54 .wasm
55 .contracts
56 .get(contract_addr)
57 {
58 local_contract.clone()
59 } else {
60 let maybe_distant_contract = WasmRemoteQuerier::load_distant_contract(
61 self.fork_state.remote.clone(),
62 &addr,
63 );
64
65 if let Ok(contract) = maybe_distant_contract {
66 contract
67 } else {
68 return (
69 SystemResult::Err(SystemError::NoSuchContract {
70 addr: contract_addr.to_string(),
71 }),
72 GasInfo::with_externally_used(GAS_COST_CONTRACT_INFO),
73 );
74 }
75 };
76 let response =
77 ContractInfoResponse::new(data.code_id, data.creator, data.admin, false, None);
78 (
79 SystemResult::Ok(to_json_binary(&response).into()),
80 GasInfo::with_externally_used(GAS_COST_CONTRACT_INFO),
81 )
82 }
83 WasmQuery::Raw { contract_addr, key } => {
84 let mut total_key =
86 get_full_contract_storage_namespace(&Addr::unchecked(contract_addr)).to_vec();
87 total_key.extend_from_slice(key);
88
89 if let Some(value) = self
90 .fork_state
91 .querier_storage
92 .wasm
93 .storage
94 .iter()
95 .find(|e| e.0 == total_key)
96 {
97 (
98 SystemResult::Ok(ContractResult::Ok(value.1.clone().into())),
99 GasInfo::with_externally_used(GAS_COST_RAW_COSMWASM_QUERY),
100 )
101 } else {
102 (
103 SystemResult::Ok(
104 WasmRemoteQuerier::raw_query(
105 remote,
106 &Addr::unchecked(contract_addr),
107 key.clone(),
108 )
109 .map(Into::into)
110 .into(),
111 ),
112 GasInfo::with_externally_used(GAS_COST_RAW_COSMWASM_QUERY),
113 )
114 }
115 }
116 WasmQuery::Smart { contract_addr, msg } => {
117 let addr = Addr::unchecked(contract_addr);
118
119 let mut storage = MockStorage::default();
120 for (key, value) in self
122 .fork_state
123 .querier_storage
124 .wasm
125 .get_contract_storage(&addr)
126 {
127 storage.set(&key, &value);
128 }
129
130 let deps = OwnedDeps {
131 storage,
132 api: MockApiBech32::new(&self.fork_state.remote.pub_address_prefix),
133 querier: MockQuerier::new(self.fork_state.clone()),
134 custom_query_type: PhantomData::<QueryC>,
135 };
136 let mut env = self.fork_state.local_state.env.clone();
137 env.contract = ContractInfo {
138 address: addr.clone(),
139 };
140
141 let code_id = if let Some(local_contract) = self
143 .fork_state
144 .querier_storage
145 .wasm
146 .contracts
147 .get(contract_addr)
148 {
149 local_contract.code_id
150 } else {
151 let wasm_querier = CosmWasm::new_sync(remote.channel.clone(), &remote.rt);
152
153 let code_info = remote
154 .rt
155 .block_on(wasm_querier._contract_info(&addr))
156 .unwrap();
157
158 code_info.code_id
159 };
160
161 let result = if let Some(code) = self
165 .fork_state
166 .querier_storage
167 .wasm
168 .codes
169 .get(&(code_id as usize))
170 {
171 <WasmContract as Contract<ExecC, QueryC>>::query(
173 code,
174 deps.as_ref(),
175 env,
176 msg.to_vec(),
177 self.fork_state.clone(),
178 )
179 } else if let Some(local_contract) = self
180 .fork_state
181 .local_state
182 .contracts
183 .get(&(code_id as usize))
184 {
185 unsafe {
187 local_contract.as_ref().unwrap().query(
188 deps.as_ref(),
189 env,
190 msg.to_vec(),
191 self.fork_state.clone(),
192 )
193 }
194 } else {
195 <WasmContract as Contract<ExecC, QueryC>>::query(
199 &WasmContract::new_distant_code_id(code_id, remote.clone()),
200 deps.as_ref(),
201 env,
202 msg.to_vec(),
203 self.fork_state.clone(),
204 )
205 };
206
207 let result = match result {
208 Err(e) => {
209 return (
210 SystemResult::Err(SystemError::InvalidRequest {
211 error: format!("Error querying a contract: {}", e),
212 request: msg.clone(),
213 }),
214 GasInfo::with_externally_used(0),
215 )
216 }
217 Ok(result) => result,
218 };
219
220 (
221 SystemResult::Ok(ContractResult::Ok(result)),
222 GasInfo::with_externally_used(GAS_COST_ALL_QUERIES),
223 )
224 }
225 WasmQuery::CodeInfo { code_id } => {
226 let code_data = self
227 .fork_state
228 .querier_storage
229 .wasm
230 .code_data
231 .get(&(*code_id as usize));
232 let res = if let Some(code_data) = code_data {
233 cosmwasm_std::CodeInfoResponse::new(
234 *code_id,
235 code_data.creator.clone(),
236 code_data.checksum,
237 )
238 } else {
239 let maybe_code_info =
240 WasmRemoteQuerier::code_info(self.fork_state.remote.clone(), *code_id);
241
242 if let Ok(code_info) = maybe_code_info {
243 code_info
244 } else {
245 return (
246 SystemResult::Err(SystemError::NoSuchCode { code_id: *code_id }),
247 GasInfo::with_externally_used(GAS_COST_CONTRACT_INFO),
248 );
249 }
250 };
251 (
252 SystemResult::Ok(to_json_binary(&res).into()),
253 GasInfo::with_externally_used(GAS_COST_CONTRACT_INFO),
254 )
255 }
256 _ => unimplemented!(),
257 }
258 }
259}