clone_cw_multi_test/
wasm.rs

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
34//TODO Make `CONTRACTS` private in version 1.0 when the function AddressGenerator::next_address will be removed.
35/// Contract state kept in storage, separate from the contracts themselves (contract code).
36pub(crate) const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts");
37
38//TODO Make `NAMESPACE_WASM` private in version 1.0 when the function AddressGenerator::next_address will be removed.
39pub(crate) const NAMESPACE_WASM: &[u8] = b"wasm";
40/// See <https://github.com/chipshort/wasmd/blob/d0e3ed19f041e65f112d8e800416b3230d0005a2/x/wasm/types/events.go#L58>
41const 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/// Contract data includes information about contract,
61/// equivalent of `ContractInfo` in `wasmd` interface.
62#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
63pub struct ContractData {
64    /// Identifier of stored contract code
65    pub code_id: u64,
66    /// Address of account who initially instantiated the contract
67    pub creator: Addr,
68    /// Optional address of account who can execute migrations
69    pub admin: Option<Addr>,
70}
71
72#[derive(Serialize, Deserialize, Debug, Clone)]
73/// Contract code base data.
74pub struct CodeData {
75    /// Address of an account that initially stored the contract code.
76    pub creator: Addr,
77    /// Checksum of the contract's code base.
78    pub checksum: Checksum,
79    /// Identifier of the code base where the contract code is stored in memory.
80    pub code_base_id: usize,
81}
82
83pub trait Wasm<ExecC, QueryC: CustomQuery>: AllWasmQuerier {
84    /// Handles all WasmQuery requests
85    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    /// Handles all `WasmMsg` messages.
96    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    /// Handles all sudo messages, this is an admin interface and can not be called via `CosmosMsg`.
107    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    /// Stores the contract's code and returns an identifier of the stored contract's code.
118    fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64;
119
120    /// Stores the contract's code and returns an identifier of the stored contract's code.
121    fn store_wasm_code(&mut self, creator: Addr, code: Vec<u8>) -> u64;
122
123    /// Returns `ContractData` for the contract with specified address.
124    fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult<ContractData>;
125
126    /// Returns a raw state dump of all key-values held by a contract with specified address.
127    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    /// Contract codes that stand for wasm code in real-life blockchain.
133    pub code_base: RefCell<HashMap<usize, WasmContract>>,
134    /// Contract codes that stand for rust code living in the current instance
135    /// We also associate the queries to them to make sure we are able to use them with the vm instance
136    pub rust_codes: HashMap<usize, LocalRustContract<ExecC, QueryC>>,
137    /// Code data with code base identifier and additional attributes.  
138    pub code_data: HashMap<usize, CodeData>,
139    /// Contract's address generator.
140    address_generator: Box<dyn AddressGenerator>,
141    /// Contract's code checksum generator.
142    checksum_generator: Box<dyn ChecksumGenerator>,
143    // chain on which the contract should be queried/tested against
144    remote: Option<RemoteChannel>,
145    /// Just markers to make type elision fork when using it as `Wasm` trait
146    _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    /// Stores the contract's code in the in-memory lookup table.
262    /// Returns an identifier of the stored contract code.
263    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    /// Stores the contract's code in the in-memory lookup table.
284    /// Returns an identifier of the stored contract code.
285    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    /// Returns `ContractData` for the contract with specified address.
306    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    /// Returns a raw state dump of all key-values held by a contract with specified address.
316    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    /// Only for Clone-testing
333    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    /// Returns a handler to code of the contract with specified code id.
353    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            // We fetch the code and save the corresponding module in memory
374            let wasm_contract =
375                WasmContract::new_distant_code_id(code_id, self.remote.clone().unwrap());
376
377            // We save it in memory
378            self.code_base
379                .borrow_mut()
380                .insert(code_id as usize, wasm_contract.clone());
381
382            // And return a Owned reference
383            Ok(ContractBox::Owned(Box::new(wasm_contract)))
384        }
385    }
386
387    /// Returns code data of the contract with specified code id.
388    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        // We double-namespace this, once from global storage -> wasm_storage
420        // then from wasm_storage -> the contracts subspace
421        let namespace = self.contract_namespace(address);
422        let storage = PrefixedStorage::multilevel(storage, &[NAMESPACE_WASM, &namespace]);
423
424        Box::new(storage)
425    }
426
427    // fails RUNTIME if you try to write. please don't
428    fn contract_storage_readonly<'a>(
429        &self,
430        storage: &'a dyn Storage,
431        address: &Addr,
432    ) -> Box<dyn Storage + 'a> {
433        // We double-namespace this, once from global storage -> wasm_storage
434        // then from wasm_storage -> the contracts subspace
435        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    /// Validates all attributes.
483    ///
484    /// In `wasmd`, before version v0.45.0 empty attribute values were not allowed.
485    /// Since `wasmd` v0.45.0 empty attribute values are allowed,
486    /// so the value is not validated anymore.
487    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    /// Executes the contract's `query` entry-point.
519    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    /// unified logic for UpdateAdmin and ClearAdmin messages
590    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        // check admin status
602        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        // update admin field
607        data.admin = admin;
608        self.save_contract(storage, &contract_addr, &data)?;
609
610        // no custom event here
611        Ok(AppResponse {
612            data: None,
613            events: vec![],
614        })
615    }
616
617    // this returns the contract address as well, so we can properly resend the data
618    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                // first move the cash
635                self.send(
636                    api,
637                    storage,
638                    router,
639                    block,
640                    sender.clone(),
641                    contract_addr.clone().into(),
642                    &funds,
643                )?;
644
645                // then call the contract
646                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                // We don't check if the code exists here, the call_migrate hook, will take care of that
707                // This allows migrating to an on-chain code_id
708                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                // then call migrate
716                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    /// Processes WasmMsg::Instantiate and WasmMsg::Instantiate2 messages.
748    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        // move the cash
778        self.send(
779            api,
780            storage,
781            router,
782            block,
783            sender.clone(),
784            contract_addr.clone().into(),
785            &funds,
786        )?;
787
788        // then call the contract
789        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    /// This will execute the given messages, making all changes to the local cache.
822    /// This *will* write some data to the cache if the message fails half-way through.
823    /// All sequential calls to RouterCache will be one atomic unit (all commit or all fail).
824    ///
825    /// For normal use cases, you can use Router::execute() or Router::execute_multi().
826    /// This is designed to be handled internally as part of larger process flows.
827    ///
828    /// The `data` on `AppResponse` is data returned from `reply` call, not from execution of
829    /// sub-message itself. In case if `reply` is not called, no `data` is set.
830    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        // execute in cache
844        let res = transactional(storage, |write_cache, _| {
845            router.execute(api, write_cache, block, contract.clone(), msg)
846        });
847
848        // call reply if meaningful
849        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                // do reply and combine it with the original response
865                let reply_res = self.reply(api, router, storage, block, contract, reply)?;
866                // override data
867                r.data = reply_res.data;
868                // append the events
869                r.events.extend_from_slice(&reply_res.events);
870            } else {
871                // reply is not called, no data should be returned
872                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    // this captures all the events and data from the contract call.
918    // it does not handle the messages
919    fn build_app_response(
920        &self,
921        contract: &Addr,
922        custom_event: Event, // entry-point specific custom event added by x/wasm
923        response: Response<ExecC>,
924    ) -> (AppResponse, Vec<SubMsg<ExecC>>) {
925        let Response {
926            messages,
927            attributes,
928            events,
929            data,
930            ..
931        } = response;
932
933        // always add custom event
934        let mut app_events = Vec::with_capacity(2 + events.len());
935        app_events.push(custom_event);
936
937        // we only emit the `wasm` event if some attributes are specified
938        if !attributes.is_empty() {
939            // turn attributes into event and place it first
940            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        // These need to get `wasm-` prefix to match the wasmd semantics (custom wasm messages cannot
947        // fake system level event types, like transfer from the bank module)
948        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        // recurse in all messages
976        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    /// Creates a contract address and empty storage instance.
987    /// Returns the new contract address.
988    ///
989    /// You have to call init after this to set up the contract properly.
990    /// These two steps are separated to have cleaner return values.
991    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        // We don't error if the code id doesn't exist, it allows us to instantiate remote contracts
1003        // generate a new contract address
1004        let instance_id = self.instance_count(storage) as u64;
1005        let addr = if let Some(salt_binary) = salt.into() {
1006            // generate predictable contract address when salt is provided
1007            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            // generate non-predictable contract address
1020            self.address_generator
1021                .contract_address(api, storage, code_id, instance_id)?
1022        };
1023
1024        // contract with the same address must not already exist
1025        if self.contract_data(storage, &addr).is_ok() {
1026            bail!(Error::duplicated_contract_address(addr));
1027        }
1028
1029        // prepare contract data and save new contract instance
1030        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        // We don't actually need a transaction here, as it is already embedded in a transactional.
1264        // execute_submsg or App.execute_multi.
1265        // However, we need to get write and read access to the same storage in two different objects,
1266        // and this is the only way I know how to do so.
1267        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    /// Returns the number of all contract instances.
1293    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// TODO: replace with code in utils
1306
1307#[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
1315// TODO: encode helpers in utils
1316fn 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    // the data must encode successfully
1324    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
1334// empty return if no data present in original
1335fn 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        // the data must encode successfully
1340        exec_data.encode(&mut new_data).unwrap();
1341        new_data.into()
1342    })
1343}