1use crate::addresses::{AddressGenerator, SimpleAddressGenerator};
2use crate::app::{CosmosRouter, RouterQuerier};
3use crate::checksums::{ChecksumGenerator, SimpleChecksumGenerator};
4use crate::contracts::Contract;
5use crate::error::{bail, AnyContext, AnyError, AnyResult, Error};
6use crate::executor::AppResponse;
7use crate::prefixed_storage::contract_namespace;
8use crate::prefixed_storage::{prefixed, prefixed_read, PrefixedStorage, ReadonlyPrefixedStorage};
9use crate::queries::wasm::WasmRemoteQuerier;
10use crate::transactions::transactional;
11use crate::wasm_emulation::channel::RemoteChannel;
12use crate::wasm_emulation::contract::{LocalWasmContract, WasmContract};
13use crate::wasm_emulation::input::QuerierStorage;
14use crate::wasm_emulation::instance::create_module;
15use crate::wasm_emulation::query::mock_querier::{ForkState, LocalForkedState};
16use crate::wasm_emulation::query::AllWasmQuerier;
17use cosmwasm_std::testing::mock_wasmd_attr;
18use cosmwasm_std::{
19 to_json_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, ContractInfo,
20 ContractInfoResponse, CustomQuery, Deps, DepsMut, Env, Event, MessageInfo, Order, Querier,
21 QuerierWrapper, Record, Reply, ReplyOn, Response, StdResult, Storage, SubMsg, SubMsgResponse,
22 SubMsgResult, TransactionInfo, WasmMsg, WasmQuery,
23};
24use cosmwasm_std::{Checksum, CustomMsg};
25use cw_storage_plus::Map;
26use prost::Message;
27use schemars::JsonSchema;
28use serde::de::DeserializeOwned;
29use serde::{Deserialize, Serialize};
30use std::cell::RefCell;
31use std::collections::HashMap;
32use std::fmt::Debug;
33
34pub(crate) const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts");
37
38pub(crate) const NAMESPACE_WASM: &[u8] = b"wasm";
40const CONTRACT_ATTR: &str = "_contract_address";
42pub const LOCAL_WASM_CODE_OFFSET: usize = 5_000_000;
43pub const LOCAL_RUST_CODE_OFFSET: usize = 10_000_000;
44
45#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)]
46pub struct WasmSudo {
47 pub contract_addr: Addr,
48 pub msg: Binary,
49}
50
51impl WasmSudo {
52 pub fn new<T: Serialize>(contract_addr: &Addr, msg: &T) -> StdResult<WasmSudo> {
53 Ok(WasmSudo {
54 contract_addr: contract_addr.clone(),
55 msg: to_json_binary(msg)?,
56 })
57 }
58}
59
60#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
63pub struct ContractData {
64 pub code_id: u64,
66 pub creator: Addr,
68 pub admin: Option<Addr>,
70}
71
72#[derive(Serialize, Deserialize, Debug, Clone)]
73pub struct CodeData {
75 pub creator: Addr,
77 pub checksum: Checksum,
79 pub code_base_id: usize,
81}
82
83pub trait Wasm<ExecC, QueryC: CustomQuery>: AllWasmQuerier {
84 fn query(
86 &self,
87 api: &dyn Api,
88 storage: &dyn Storage,
89 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
90 querier: &dyn Querier,
91 block: &BlockInfo,
92 request: WasmQuery,
93 ) -> AnyResult<Binary>;
94
95 fn execute(
97 &self,
98 api: &dyn Api,
99 storage: &mut dyn Storage,
100 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
101 block: &BlockInfo,
102 sender: Addr,
103 msg: WasmMsg,
104 ) -> AnyResult<AppResponse>;
105
106 fn sudo(
108 &self,
109 api: &dyn Api,
110 contract_addr: Addr,
111 storage: &mut dyn Storage,
112 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
113 block: &BlockInfo,
114 msg: Binary,
115 ) -> AnyResult<AppResponse>;
116
117 fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64;
119
120 fn store_wasm_code(&mut self, creator: Addr, code: Vec<u8>) -> u64;
122
123 fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult<ContractData>;
125
126 fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record>;
128}
129
130pub type LocalRustContract<ExecC, QueryC> = *mut dyn Contract<ExecC, QueryC>;
131pub struct WasmKeeper<ExecC: 'static, QueryC: CustomQuery + 'static> {
132 pub code_base: RefCell<HashMap<usize, WasmContract>>,
134 pub rust_codes: HashMap<usize, LocalRustContract<ExecC, QueryC>>,
137 pub code_data: HashMap<usize, CodeData>,
139 address_generator: Box<dyn AddressGenerator>,
141 checksum_generator: Box<dyn ChecksumGenerator>,
143 remote: Option<RemoteChannel>,
145 _p: std::marker::PhantomData<(ExecC, QueryC)>,
147}
148
149impl<ExecC, QueryC: CustomQuery> Default for WasmKeeper<ExecC, QueryC> {
150 fn default() -> WasmKeeper<ExecC, QueryC> {
151 Self {
152 code_base: HashMap::new().into(),
153 code_data: HashMap::new(),
154 address_generator: Box::new(SimpleAddressGenerator),
155 checksum_generator: Box::new(SimpleChecksumGenerator),
156 _p: std::marker::PhantomData,
157 remote: None,
158 rust_codes: HashMap::new(),
159 }
160 }
161}
162
163impl<ExecC, QueryC> Wasm<ExecC, QueryC> for WasmKeeper<ExecC, QueryC>
164where
165 ExecC: CustomMsg + DeserializeOwned + 'static,
166 QueryC: CustomQuery + DeserializeOwned + 'static,
167{
168 fn query(
169 &self,
170 api: &dyn Api,
171 storage: &dyn Storage,
172 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
173 querier: &dyn Querier,
174 block: &BlockInfo,
175 request: WasmQuery,
176 ) -> AnyResult<Binary> {
177 match request {
178 WasmQuery::Smart { contract_addr, msg } => {
179 let addr = api.addr_validate(&contract_addr)?;
180 self.query_smart(
181 addr,
182 api,
183 storage,
184 querier,
185 block,
186 msg.into(),
187 router.get_querier_storage(storage)?,
188 )
189 }
190 WasmQuery::Raw { contract_addr, key } => {
191 let addr = api.addr_validate(&contract_addr)?;
192 Ok(self.query_raw(addr, storage, &key))
193 }
194 WasmQuery::ContractInfo { contract_addr } => {
195 let addr = api.addr_validate(&contract_addr)?;
196 let contract = self.contract_data(storage, &addr)?;
197 let res = ContractInfoResponse::new(
198 contract.code_id,
199 contract.creator,
200 contract.admin,
201 false,
202 None,
203 );
204 to_json_binary(&res).map_err(Into::into)
205 }
206 WasmQuery::CodeInfo { code_id } => {
207 let code_data = self.code_data(code_id)?;
208 let res = cosmwasm_std::CodeInfoResponse::new(
209 code_id,
210 code_data.creator,
211 code_data.checksum,
212 );
213 to_json_binary(&res).map_err(Into::into)
214 }
215 other => bail!(Error::UnsupportedWasmQuery(other)),
216 }
217 }
218
219 fn execute(
220 &self,
221 api: &dyn Api,
222 storage: &mut dyn Storage,
223 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
224 block: &BlockInfo,
225 sender: Addr,
226 msg: WasmMsg,
227 ) -> AnyResult<AppResponse> {
228 self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone())
229 .context(format!(
230 "Error executing WasmMsg:\n sender: {}\n {:?}",
231 sender, msg
232 ))
233 }
234
235 fn sudo(
236 &self,
237 api: &dyn Api,
238 contract: Addr,
239 storage: &mut dyn Storage,
240 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
241 block: &BlockInfo,
242 msg: Binary,
243 ) -> AnyResult<AppResponse> {
244 let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &contract);
245
246 let querier_storage = router.get_querier_storage(storage)?;
247
248 let res = self.call_sudo(
249 contract.clone(),
250 api,
251 storage,
252 router,
253 block,
254 msg.to_vec(),
255 querier_storage,
256 )?;
257 let (res, msgs) = self.build_app_response(&contract, custom_event, res);
258 self.process_response(api, router, storage, block, contract, res, msgs)
259 }
260
261 fn store_wasm_code(&mut self, creator: Addr, code: Vec<u8>) -> u64 {
264 let code_id = self.code_base.borrow().len() + 1 + LOCAL_WASM_CODE_OFFSET;
265 let code = WasmContract::Local(LocalWasmContract {
266 module: create_module(&code).unwrap(),
267 code,
268 });
269
270 self.code_base.borrow_mut().insert(code_id, code);
271 let checksum = self.checksum_generator.checksum(&creator, code_id as u64);
272 self.code_data.insert(
273 code_id,
274 CodeData {
275 creator,
276 checksum,
277 code_base_id: code_id,
278 },
279 );
280 code_id as u64
281 }
282
283 fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64 {
286 let code_id = self.rust_codes.len() + 1 + LOCAL_RUST_CODE_OFFSET;
287 let checksum = code
288 .checksum()
289 .unwrap_or(self.checksum_generator.checksum(&creator, code_id as u64));
290 let static_ref = Box::leak(code);
291
292 let raw_pointer = static_ref as *mut dyn Contract<ExecC, QueryC>;
293 self.rust_codes.insert(code_id, raw_pointer);
294 self.code_data.insert(
295 code_id,
296 CodeData {
297 creator,
298 checksum,
299 code_base_id: code_id,
300 },
301 );
302 code_id as u64
303 }
304
305 fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult<ContractData> {
307 let contract = CONTRACTS.load(&prefixed_read(storage, NAMESPACE_WASM), address);
308 if let Ok(local_contract) = contract {
309 Ok(local_contract)
310 } else {
311 WasmRemoteQuerier::load_distant_contract(self.remote.clone().unwrap(), address)
312 }
313 }
314
315 fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record> {
317 let storage = self.contract_storage_readonly(storage, address);
318 storage.range(None, None, Order::Ascending).collect()
319 }
320}
321
322pub enum ContractBox<'a, ExecC, QueryC> {
323 Borrowed(&'a dyn Contract<ExecC, QueryC>),
324 Owned(Box<dyn Contract<ExecC, QueryC>>),
325}
326
327impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC>
328where
329 ExecC: CustomMsg + DeserializeOwned + 'static,
330 QueryC: CustomQuery + DeserializeOwned + 'static,
331{
332 fn fork_state(
334 &self,
335 querier_storage: QuerierStorage,
336 env: &Env,
337 ) -> AnyResult<ForkState<ExecC, QueryC>> {
338 Ok(ForkState {
339 remote: self.remote.clone().unwrap(),
340 querier_storage,
341 local_state: LocalForkedState {
342 contracts: self
343 .rust_codes
344 .iter()
345 .map(|(id, &code)| (*id, code))
346 .collect(),
347 env: env.clone(),
348 },
349 })
350 }
351
352 pub fn contract_code<'a, 'b>(
354 &'a self,
355 code_id: u64,
356 ) -> AnyResult<ContractBox<'a, ExecC, QueryC>>
357 where
358 'a: 'b,
359 {
360 let code_data = self.code_data(code_id)?;
361 let code = self
362 .code_base
363 .borrow()
364 .get(&code_data.code_base_id)
365 .cloned();
366 if let Some(code) = code {
367 Ok(ContractBox::Owned(Box::new(code)))
368 } else if let Some(&rust_code) = self.rust_codes.get(&code_data.code_base_id) {
369 Ok(ContractBox::Borrowed(unsafe {
370 rust_code.as_ref().unwrap()
371 }))
372 } else {
373 let wasm_contract =
375 WasmContract::new_distant_code_id(code_id, self.remote.clone().unwrap());
376
377 self.code_base
379 .borrow_mut()
380 .insert(code_id as usize, wasm_contract.clone());
381
382 Ok(ContractBox::Owned(Box::new(wasm_contract)))
384 }
385 }
386
387 fn code_data(&self, code_id: u64) -> AnyResult<CodeData> {
389 if code_id < 1 {
390 bail!(Error::InvalidCodeId);
391 }
392 if let Some(code_data) = self.code_data.get(&(code_id as usize)) {
393 Ok(code_data.clone())
394 } else {
395 let code_info_response =
396 WasmRemoteQuerier::code_info(self.remote.clone().unwrap(), code_id)?;
397 Ok(CodeData {
398 creator: Addr::unchecked(code_info_response.creator),
399 checksum: code_info_response.checksum,
400 code_base_id: code_id as usize,
401 })
402 }
403 }
404
405 pub fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record> {
406 let storage = self.contract_storage_readonly(storage, address);
407 storage.range(None, None, Order::Ascending).collect()
408 }
409
410 fn contract_namespace(&self, contract: &Addr) -> Vec<u8> {
411 contract_namespace(contract)
412 }
413
414 fn contract_storage<'a>(
415 &self,
416 storage: &'a mut dyn Storage,
417 address: &Addr,
418 ) -> Box<dyn Storage + 'a> {
419 let namespace = self.contract_namespace(address);
422 let storage = PrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]);
423
424 Box::new(storage)
425 }
426
427 fn contract_storage_readonly<'a>(
429 &self,
430 storage: &'a dyn Storage,
431 address: &Addr,
432 ) -> Box<dyn Storage + 'a> {
433 let namespace = self.contract_namespace(address);
436 let storage = ReadonlyPrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]);
437 Box::new(storage)
438 }
439}
440impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC>
441where
442 ExecC: CustomMsg + DeserializeOwned + 'static,
443 QueryC: CustomQuery + DeserializeOwned + 'static,
444{
445 pub fn new() -> Self {
446 Self::default()
447 }
448
449 #[deprecated(
450 since = "0.18.0",
451 note = "use `WasmKeeper::new().with_address_generator` instead; will be removed in version 1.0.0"
452 )]
453 pub fn new_with_custom_address_generator(
454 address_generator: impl AddressGenerator + 'static,
455 ) -> Self {
456 Self {
457 address_generator: Box::new(address_generator),
458 ..Default::default()
459 }
460 }
461
462 pub fn with_remote(mut self, remote: RemoteChannel) -> Self {
463 self.remote = Some(remote);
464 self
465 }
466 pub fn with_address_generator(
467 mut self,
468 address_generator: impl AddressGenerator + 'static,
469 ) -> Self {
470 self.address_generator = Box::new(address_generator);
471 self
472 }
473
474 pub fn with_checksum_generator(
475 mut self,
476 checksum_generator: impl ChecksumGenerator + 'static,
477 ) -> Self {
478 self.checksum_generator = Box::new(checksum_generator);
479 self
480 }
481
482 fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> {
488 for attr in attributes {
489 let key = attr.key.trim();
490 let val = attr.value.trim();
491 if key.is_empty() {
492 bail!(Error::empty_attribute_key(val));
493 }
494 if key.starts_with('_') {
495 bail!(Error::reserved_attribute_key(key));
496 }
497 }
498 Ok(())
499 }
500
501 fn verify_response<T>(response: Response<T>) -> AnyResult<Response<T>>
502 where
503 T: CustomMsg,
504 {
505 Self::verify_attributes(&response.attributes)?;
506
507 for event in &response.events {
508 Self::verify_attributes(&event.attributes)?;
509 let ty = event.ty.trim();
510 if ty.len() < 2 {
511 bail!(Error::event_type_too_short(ty));
512 }
513 }
514
515 Ok(response)
516 }
517
518 pub fn query_smart(
520 &self,
521 address: Addr,
522 api: &dyn Api,
523 storage: &dyn Storage,
524 querier: &dyn Querier,
525 block: &BlockInfo,
526 msg: Vec<u8>,
527 querier_storage: QuerierStorage,
528 ) -> AnyResult<Binary> {
529 self.with_storage_readonly(
530 api,
531 storage,
532 querier,
533 block,
534 address,
535 |handler, deps, env| match handler {
536 ContractBox::Borrowed(contract) => contract.query(
537 deps,
538 env.clone(),
539 msg,
540 self.fork_state(querier_storage, &env)?,
541 ),
542 ContractBox::Owned(contract) => contract.query(
543 deps,
544 env.clone(),
545 msg,
546 self.fork_state(querier_storage, &env)?,
547 ),
548 },
549 )
550 }
551
552 pub fn query_raw(&self, address: Addr, storage: &dyn Storage, key: &[u8]) -> Binary {
553 let local_key = self.contract_storage_readonly(storage, &address).get(key);
554 if let Some(local_key) = local_key {
555 local_key.into()
556 } else {
557 WasmRemoteQuerier::raw_query(self.remote.clone().unwrap(), &address, key.into())
558 .unwrap_or_default()
559 .into()
560 }
561 }
562
563 fn send<T>(
564 &self,
565 api: &dyn Api,
566 storage: &mut dyn Storage,
567 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
568 block: &BlockInfo,
569 sender: T,
570 recipient: String,
571 amount: &[Coin],
572 ) -> AnyResult<AppResponse>
573 where
574 T: Into<Addr>,
575 {
576 if !amount.is_empty() {
577 let msg: cosmwasm_std::CosmosMsg<ExecC> = BankMsg::Send {
578 to_address: recipient,
579 amount: amount.to_vec(),
580 }
581 .into();
582 let res = router.execute(api, storage, block, sender.into(), msg)?;
583 Ok(res)
584 } else {
585 Ok(AppResponse::default())
586 }
587 }
588
589 fn update_admin(
591 &self,
592 api: &dyn Api,
593 storage: &mut dyn Storage,
594 sender: Addr,
595 contract_addr: &str,
596 new_admin: Option<String>,
597 ) -> AnyResult<AppResponse> {
598 let contract_addr = api.addr_validate(contract_addr)?;
599 let admin = new_admin.map(|a| api.addr_validate(&a)).transpose()?;
600
601 let mut data = self.contract_data(storage, &contract_addr)?;
603 if data.admin != Some(sender) {
604 bail!("Only admin can update the contract admin: {:?}", data.admin);
605 }
606 data.admin = admin;
608 self.save_contract(storage, &contract_addr, &data)?;
609
610 Ok(AppResponse {
612 data: None,
613 events: vec![],
614 })
615 }
616
617 fn execute_wasm(
619 &self,
620 api: &dyn Api,
621 storage: &mut dyn Storage,
622 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
623 block: &BlockInfo,
624 sender: Addr,
625 wasm_msg: WasmMsg,
626 ) -> AnyResult<AppResponse> {
627 match wasm_msg {
628 WasmMsg::Execute {
629 contract_addr,
630 msg,
631 funds,
632 } => {
633 let contract_addr = api.addr_validate(&contract_addr)?;
634 self.send(
636 api,
637 storage,
638 router,
639 block,
640 sender.clone(),
641 contract_addr.clone().into(),
642 &funds,
643 )?;
644
645 let info = MessageInfo { sender, funds };
647 let querier_storage = router.get_querier_storage(storage)?;
648
649 let res = self.call_execute(
650 api,
651 storage,
652 contract_addr.clone(),
653 router,
654 block,
655 info,
656 msg.to_vec(),
657 querier_storage,
658 )?;
659
660 let custom_event =
661 Event::new("execute").add_attribute(CONTRACT_ATTR, &contract_addr);
662
663 let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
664
665 let mut res =
666 self.process_response(api, router, storage, block, contract_addr, res, msgs)?;
667 res.data = execute_response(res.data);
668 Ok(res)
669 }
670 WasmMsg::Instantiate {
671 admin,
672 code_id,
673 msg,
674 funds,
675 label,
676 } => self.process_wasm_msg_instantiate(
677 api, storage, router, block, sender, admin, code_id, msg, funds, label, None,
678 ),
679 WasmMsg::Instantiate2 {
680 admin,
681 code_id,
682 msg,
683 funds,
684 label,
685 salt,
686 } => self.process_wasm_msg_instantiate(
687 api,
688 storage,
689 router,
690 block,
691 sender,
692 admin,
693 code_id,
694 msg,
695 funds,
696 label,
697 Some(salt),
698 ),
699 WasmMsg::Migrate {
700 contract_addr,
701 new_code_id,
702 msg,
703 } => {
704 let contract_addr = api.addr_validate(&contract_addr)?;
705
706 let mut data = self.contract_data(storage, &contract_addr)?;
709 if data.admin != Some(sender) {
710 bail!("Only admin can migrate contract: {:?}", data.admin);
711 }
712 data.code_id = new_code_id;
713 self.save_contract(storage, &contract_addr, &data)?;
714
715 let querier_storage = router.get_querier_storage(storage)?;
717 let res = self.call_migrate(
718 contract_addr.clone(),
719 api,
720 storage,
721 router,
722 block,
723 msg.to_vec(),
724 querier_storage,
725 )?;
726
727 let custom_event = Event::new("migrate")
728 .add_attribute(CONTRACT_ATTR, &contract_addr)
729 .add_attribute("code_id", new_code_id.to_string());
730 let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
731 let mut res =
732 self.process_response(api, router, storage, block, contract_addr, res, msgs)?;
733 res.data = execute_response(res.data);
734 Ok(res)
735 }
736 WasmMsg::UpdateAdmin {
737 contract_addr,
738 admin,
739 } => self.update_admin(api, storage, sender, &contract_addr, Some(admin)),
740 WasmMsg::ClearAdmin { contract_addr } => {
741 self.update_admin(api, storage, sender, &contract_addr, None)
742 }
743 msg => bail!(Error::UnsupportedWasmMsg(msg)),
744 }
745 }
746
747 fn process_wasm_msg_instantiate(
749 &self,
750 api: &dyn Api,
751 storage: &mut dyn Storage,
752 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
753 block: &BlockInfo,
754 sender: Addr,
755 admin: Option<String>,
756 code_id: u64,
757 msg: Binary,
758 funds: Vec<Coin>,
759 label: String,
760 salt: Option<Binary>,
761 ) -> AnyResult<AppResponse> {
762 if label.is_empty() {
763 bail!("Label is required on all contracts");
764 }
765
766 let contract_addr = self.register_contract(
767 api,
768 storage,
769 code_id,
770 sender.clone(),
771 admin.map(Addr::unchecked),
772 label,
773 block.height,
774 salt,
775 )?;
776
777 self.send(
779 api,
780 storage,
781 router,
782 block,
783 sender.clone(),
784 contract_addr.clone().into(),
785 &funds,
786 )?;
787
788 let info = MessageInfo { sender, funds };
790 let querier_storage = router.get_querier_storage(storage)?;
791 let res = self.call_instantiate(
792 contract_addr.clone(),
793 api,
794 storage,
795 router,
796 block,
797 info,
798 msg.to_vec(),
799 querier_storage,
800 )?;
801
802 let custom_event = Event::new("instantiate")
803 .add_attribute(CONTRACT_ATTR, &contract_addr)
804 .add_attribute("code_id", code_id.to_string());
805
806 let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
807
808 let mut res = self.process_response(
809 api,
810 router,
811 storage,
812 block,
813 contract_addr.clone(),
814 res,
815 msgs,
816 )?;
817 res.data = Some(instantiate_response(res.data, &contract_addr));
818 Ok(res)
819 }
820
821 fn execute_submsg(
831 &self,
832 api: &dyn Api,
833 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
834 storage: &mut dyn Storage,
835 block: &BlockInfo,
836 contract: Addr,
837 msg: SubMsg<ExecC>,
838 ) -> AnyResult<AppResponse> {
839 let SubMsg {
840 msg, id, reply_on, ..
841 } = msg;
842
843 let res = transactional(storage, |write_cache, _| {
845 router.execute(api, write_cache, block, contract.clone(), msg)
846 });
847
848 if let Ok(mut r) = res {
850 if matches!(reply_on, ReplyOn::Always | ReplyOn::Success) {
851 let reply = Reply {
852 id,
853 result: SubMsgResult::Ok(
854 #[allow(deprecated)]
855 SubMsgResponse {
856 events: r.events.clone(),
857 data: r.data,
858 msg_responses: vec![],
859 },
860 ),
861 payload: Default::default(),
862 gas_used: 0,
863 };
864 let reply_res = self.reply(api, router, storage, block, contract, reply)?;
866 r.data = reply_res.data;
868 r.events.extend_from_slice(&reply_res.events);
870 } else {
871 r.data = None;
873 }
874
875 Ok(r)
876 } else if let Err(e) = res {
877 if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) {
878 let reply = Reply {
879 id,
880 result: SubMsgResult::Err(format!("{:?}", e)),
881 payload: Default::default(),
882 gas_used: 0,
883 };
884 self.reply(api, router, storage, block, contract, reply)
885 } else {
886 Err(e)
887 }
888 } else {
889 res
890 }
891 }
892
893 fn reply(
894 &self,
895 api: &dyn Api,
896 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
897 storage: &mut dyn Storage,
898 block: &BlockInfo,
899 contract: Addr,
900 reply: Reply,
901 ) -> AnyResult<AppResponse> {
902 let ok_attr = if reply.result.is_ok() {
903 "handle_success"
904 } else {
905 "handle_failure"
906 };
907 let custom_event = Event::new("reply")
908 .add_attribute(CONTRACT_ATTR, &contract)
909 .add_attribute("mode", ok_attr);
910
911 let res = self.call_reply(contract.clone(), api, storage, router, block, reply)?;
912 let (res, msgs) = self.build_app_response(&contract, custom_event, res);
913
914 self.process_response(api, router, storage, block, contract, res, msgs)
915 }
916
917 fn build_app_response(
920 &self,
921 contract: &Addr,
922 custom_event: Event, response: Response<ExecC>,
924 ) -> (AppResponse, Vec<SubMsg<ExecC>>) {
925 let Response {
926 messages,
927 attributes,
928 events,
929 data,
930 ..
931 } = response;
932
933 let mut app_events = Vec::with_capacity(2 + events.len());
935 app_events.push(custom_event);
936
937 if !attributes.is_empty() {
939 let wasm_event = Event::new("wasm")
941 .add_attribute(CONTRACT_ATTR, contract)
942 .add_attributes(attributes);
943 app_events.push(wasm_event);
944 }
945
946 let wasm_events = events.into_iter().map(|mut ev| {
949 ev.ty = format!("wasm-{}", ev.ty);
950 ev.attributes
951 .insert(0, mock_wasmd_attr(CONTRACT_ATTR, contract));
952 ev
953 });
954 app_events.extend(wasm_events);
955
956 let app = AppResponse {
957 events: app_events,
958 data,
959 };
960 (app, messages)
961 }
962
963 fn process_response(
964 &self,
965 api: &dyn Api,
966 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
967 storage: &mut dyn Storage,
968 block: &BlockInfo,
969 contract: Addr,
970 response: AppResponse,
971 messages: Vec<SubMsg<ExecC>>,
972 ) -> AnyResult<AppResponse> {
973 let AppResponse { mut events, data } = response;
974
975 let data = messages.into_iter().try_fold(data, |data, resend| {
977 let sub_res =
978 self.execute_submsg(api, router, storage, block, contract.clone(), resend)?;
979 events.extend_from_slice(&sub_res.events);
980 Ok::<_, AnyError>(sub_res.data.or(data))
981 })?;
982
983 Ok(AppResponse { events, data })
984 }
985
986 pub fn register_contract(
992 &self,
993 api: &dyn Api,
994 storage: &mut dyn Storage,
995 code_id: u64,
996 creator: Addr,
997 admin: impl Into<Option<Addr>>,
998 _label: String,
999 _created: u64,
1000 salt: impl Into<Option<Binary>>,
1001 ) -> AnyResult<Addr> {
1002 let instance_id = self.instance_count(storage) as u64;
1005 let addr = if let Some(salt_binary) = salt.into() {
1006 let code_data = self.code_data(code_id)?;
1008 let canonical_addr = &api.addr_canonicalize(creator.as_ref())?;
1009 self.address_generator.predictable_contract_address(
1010 api,
1011 storage,
1012 code_id,
1013 instance_id,
1014 code_data.checksum.as_slice(),
1015 canonical_addr,
1016 salt_binary.as_slice(),
1017 )?
1018 } else {
1019 self.address_generator
1021 .contract_address(api, storage, code_id, instance_id)?
1022 };
1023
1024 if self.contract_data(storage, &addr).is_ok() {
1026 bail!(Error::duplicated_contract_address(addr));
1027 }
1028
1029 let info = ContractData {
1031 code_id,
1032 creator,
1033 admin: admin.into(),
1034 };
1035 self.save_contract(storage, &addr, &info)?;
1036 Ok(addr)
1037 }
1038
1039 pub fn call_execute(
1040 &self,
1041 api: &dyn Api,
1042 storage: &mut dyn Storage,
1043 address: Addr,
1044 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1045 block: &BlockInfo,
1046 info: MessageInfo,
1047 msg: Vec<u8>,
1048 querier_storage: QuerierStorage,
1049 ) -> AnyResult<Response<ExecC>> {
1050 Self::verify_response(self.with_storage(
1051 api,
1052 storage,
1053 router,
1054 block,
1055 address,
1056 |contract, deps, env| match contract {
1057 ContractBox::Borrowed(contract) => contract.execute(
1058 deps,
1059 env.clone(),
1060 info,
1061 msg,
1062 self.fork_state(querier_storage, &env)?,
1063 ),
1064 ContractBox::Owned(contract) => contract.execute(
1065 deps,
1066 env.clone(),
1067 info,
1068 msg,
1069 self.fork_state(querier_storage, &env)?,
1070 ),
1071 },
1072 )?)
1073 }
1074
1075 pub fn call_instantiate(
1076 &self,
1077 address: Addr,
1078 api: &dyn Api,
1079 storage: &mut dyn Storage,
1080 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1081 block: &BlockInfo,
1082 info: MessageInfo,
1083 msg: Vec<u8>,
1084 querier_storage: QuerierStorage,
1085 ) -> AnyResult<Response<ExecC>> {
1086 Self::verify_response(self.with_storage(
1087 api,
1088 storage,
1089 router,
1090 block,
1091 address,
1092 |contract, deps, env| match contract {
1093 ContractBox::Borrowed(contract) => contract.instantiate(
1094 deps,
1095 env.clone(),
1096 info,
1097 msg,
1098 self.fork_state(querier_storage, &env)?,
1099 ),
1100 ContractBox::Owned(contract) => contract.instantiate(
1101 deps,
1102 env.clone(),
1103 info,
1104 msg,
1105 self.fork_state(querier_storage, &env)?,
1106 ),
1107 },
1108 )?)
1109 }
1110
1111 pub fn call_reply(
1112 &self,
1113 address: Addr,
1114 api: &dyn Api,
1115 storage: &mut dyn Storage,
1116 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1117 block: &BlockInfo,
1118 reply: Reply,
1119 ) -> AnyResult<Response<ExecC>> {
1120 let querier_storage = router.get_querier_storage(storage)?;
1121 Self::verify_response(self.with_storage(
1122 api,
1123 storage,
1124 router,
1125 block,
1126 address,
1127 |contract, deps, env| match contract {
1128 ContractBox::Borrowed(contract) => contract.reply(
1129 deps,
1130 env.clone(),
1131 reply,
1132 self.fork_state(querier_storage, &env)?,
1133 ),
1134 ContractBox::Owned(contract) => contract.reply(
1135 deps,
1136 env.clone(),
1137 reply,
1138 self.fork_state(querier_storage, &env)?,
1139 ),
1140 },
1141 )?)
1142 }
1143
1144 pub fn call_sudo(
1145 &self,
1146 address: Addr,
1147 api: &dyn Api,
1148 storage: &mut dyn Storage,
1149 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1150 block: &BlockInfo,
1151 msg: Vec<u8>,
1152 querier_storage: QuerierStorage,
1153 ) -> AnyResult<Response<ExecC>> {
1154 Self::verify_response(self.with_storage(
1155 api,
1156 storage,
1157 router,
1158 block,
1159 address,
1160 |contract, deps, env| match contract {
1161 ContractBox::Borrowed(contract) => contract.sudo(
1162 deps,
1163 env.clone(),
1164 msg,
1165 self.fork_state(querier_storage, &env)?,
1166 ),
1167 ContractBox::Owned(contract) => contract.sudo(
1168 deps,
1169 env.clone(),
1170 msg,
1171 self.fork_state(querier_storage, &env)?,
1172 ),
1173 },
1174 )?)
1175 }
1176
1177 pub fn call_migrate(
1178 &self,
1179 address: Addr,
1180 api: &dyn Api,
1181 storage: &mut dyn Storage,
1182 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1183 block: &BlockInfo,
1184 msg: Vec<u8>,
1185 querier_storage: QuerierStorage,
1186 ) -> AnyResult<Response<ExecC>> {
1187 Self::verify_response(self.with_storage(
1188 api,
1189 storage,
1190 router,
1191 block,
1192 address,
1193 |contract, deps, env| match contract {
1194 ContractBox::Borrowed(contract) => contract.migrate(
1195 deps,
1196 env.clone(),
1197 msg,
1198 self.fork_state(querier_storage, &env)?,
1199 ),
1200 ContractBox::Owned(contract) => contract.migrate(
1201 deps,
1202 env.clone(),
1203 msg,
1204 self.fork_state(querier_storage, &env)?,
1205 ),
1206 },
1207 )?)
1208 }
1209
1210 fn get_env<T: Into<Addr>>(&self, address: T, block: &BlockInfo) -> Env {
1211 Env {
1212 block: block.clone(),
1213 contract: ContractInfo {
1214 address: address.into(),
1215 },
1216 transaction: Some(TransactionInfo { index: 0 }),
1217 }
1218 }
1219
1220 fn with_storage_readonly<'a, 'b, F, T>(
1221 &'a self,
1222 api: &dyn Api,
1223 storage: &dyn Storage,
1224 querier: &dyn Querier,
1225 block: &BlockInfo,
1226 address: Addr,
1227 action: F,
1228 ) -> AnyResult<T>
1229 where
1230 F: FnOnce(ContractBox<'b, ExecC, QueryC>, Deps<QueryC>, Env) -> AnyResult<T>,
1231 'a: 'b,
1232 {
1233 let contract = self.contract_data(storage, &address)?;
1234 let handler = self.contract_code::<'a, 'b>(contract.code_id)?;
1235 let storage = self.contract_storage_readonly(storage, &address);
1236 let env = self.get_env(address, block);
1237
1238 let deps = Deps {
1239 storage: storage.as_ref(),
1240 api,
1241 querier: QuerierWrapper::new(querier),
1242 };
1243 action(handler, deps, env)
1244 }
1245
1246 fn with_storage<'a, 'b, F, T>(
1247 &'a self,
1248 api: &dyn Api,
1249 storage: &mut dyn Storage,
1250 router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1251 block: &BlockInfo,
1252 address: Addr,
1253 action: F,
1254 ) -> AnyResult<T>
1255 where
1256 F: FnOnce(ContractBox<'b, ExecC, QueryC>, DepsMut<QueryC>, Env) -> AnyResult<T>,
1257 'a: 'b,
1258 ExecC: DeserializeOwned,
1259 {
1260 let contract = self.contract_data(storage, &address)?;
1261 let handler = self.contract_code(contract.code_id)?;
1262
1263 transactional(storage, |write_cache, read_store| {
1268 let mut contract_storage = self.contract_storage(write_cache, &address);
1269 let querier = RouterQuerier::new(router, api, read_store, block);
1270 let env = self.get_env(address, block);
1271
1272 let deps = DepsMut {
1273 storage: contract_storage.as_mut(),
1274 api,
1275 querier: QuerierWrapper::new(&querier),
1276 };
1277 action(handler, deps, env)
1278 })
1279 }
1280
1281 pub fn save_contract(
1282 &self,
1283 storage: &mut dyn Storage,
1284 address: &Addr,
1285 contract: &ContractData,
1286 ) -> AnyResult<()> {
1287 CONTRACTS
1288 .save(&mut prefixed(storage, NAMESPACE_WASM), address, contract)
1289 .map_err(Into::into)
1290 }
1291
1292 fn instance_count(&self, storage: &dyn Storage) -> usize {
1294 CONTRACTS
1295 .range_raw(
1296 &prefixed_read(storage, NAMESPACE_WASM),
1297 None,
1298 None,
1299 Order::Ascending,
1300 )
1301 .count()
1302 }
1303}
1304
1305#[derive(Clone, PartialEq, Message)]
1308struct InstantiateResponse {
1309 #[prost(string, tag = "1")]
1310 pub address: ::prost::alloc::string::String,
1311 #[prost(bytes, tag = "2")]
1312 pub data: ::prost::alloc::vec::Vec<u8>,
1313}
1314
1315fn instantiate_response(data: Option<Binary>, contact_address: &Addr) -> Binary {
1317 let data = data.unwrap_or_default().to_vec();
1318 let init_data = InstantiateResponse {
1319 address: contact_address.into(),
1320 data,
1321 };
1322 let mut new_data = Vec::<u8>::with_capacity(init_data.encoded_len());
1323 init_data.encode(&mut new_data).unwrap();
1325 new_data.into()
1326}
1327
1328#[derive(Clone, PartialEq, Message)]
1329struct ExecuteResponse {
1330 #[prost(bytes, tag = "1")]
1331 pub data: ::prost::alloc::vec::Vec<u8>,
1332}
1333
1334fn execute_response(data: Option<Binary>) -> Option<Binary> {
1336 data.map(|d| {
1337 let exec_data = ExecuteResponse { data: d.to_vec() };
1338 let mut new_data = Vec::<u8>::with_capacity(exec_data.encoded_len());
1339 exec_data.encode(&mut new_data).unwrap();
1341 new_data.into()
1342 })
1343}