DEV Community

Vu
Vu

Posted on

Writing a smart contract with CosmWasm (Part 4)

Introduction

Continue with my series, we will perform query.
The query is an action in order to get data from the contract.

Create message query smart contracts

Same as execute, we need to define two structs QueryMsg and QueryResponse in the src/msg.rc to visualize the data type we want to receive and respond. Insert the below code:


#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    Counter {},
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct QueryResponse {
    pub counter: i32,
}
Enter fullscreen mode Exit fullscreen mode

Image description

QueryResponse is response of the smart contract return when we perform query with QueryMsg. Same as the response from API, it returns json data.

Next, create a file: query.rs in the src folder and import module query to lib.rs. Our lib.rs will show:

pub mod contract;
mod error;
pub mod execute;
pub mod msg;
pub mod query;
pub mod state;

pub use crate::error::ContractError;
Enter fullscreen mode Exit fullscreen mode

Image description

In the file query.rs, we are implementing a function with the name query_counter and we pass the deps as a parameter. The function return a StdResult<Binary>. Update the below code:

#[cfg(not(feature = "library"))]
use cosmwasm_std::{to_binary, Binary, Deps, Env, StdResult};

use crate::msg::QueryResponse;
use crate::state::STATE;

pub fn query_counter(deps: Deps, _env: Env) -> StdResult<Binary> {
    let current_state = STATE.load(deps.storage)?;
    let counter = current_state.counter;

    let resp = to_binary(&QueryResponse { counter }).unwrap();
    Ok(resp)
}
Enter fullscreen mode Exit fullscreen mode

Image description

That's right. Simple, we implement a logic to query data stored in smart contract.
We need to bind response to json data with to_binary function support from cosmwasm-std.
And don't forget add an new entry point to src/contract.rs:

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::Counter {} => query_counter(deps, env),
    }
}
Enter fullscreen mode Exit fullscreen mode

Image description

I think we have familiar with this syntax throughout of series.
The last entry point of our contract has appeared. We need to test it.

Testing module

Still in the file: src/query.rs. and update the below code to bottom:

#[cfg(test)]
mod tests {
    use crate::contract::{execute, instantiate, query};
    use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, QueryResponse};
    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
    use cosmwasm_std::to_binary;

    const ADDR: &str = "addr1";

    #[test]
    fn test_query() {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info(ADDR, &[]);
        let expect_data_0 = to_binary(&QueryResponse { counter: 0 }).unwrap();
        let expect_data_1 = to_binary(&QueryResponse { counter: 1 }).unwrap();

        let msg = InstantiateMsg {};
        let _resp = instantiate(deps.as_mut(), env.clone(), info.clone(), msg).unwrap();

        // query one time.
        let msg = QueryMsg::Counter {};
        let resp = query(deps.as_ref(), env.clone(), msg).unwrap();
        assert_eq!(resp, expect_data_0);

        // query two time
        let msg = ExecuteMsg::Update {};
        let _resp = execute(deps.as_mut(), env.clone(), info, msg).unwrap();
        let msg = QueryMsg::Counter {};
        let resp = query(deps.as_ref(), env, msg).unwrap();
        assert_eq!(resp, expect_data_1);
    }
}
Enter fullscreen mode Exit fullscreen mode

Image description

In query testing module, we will coverage all logic of the smart contract includes: create contract, execute contract, and query contract.

We create a module test and unit test function test_query.
We still import all dependencies and create two values expected. One for getting state after instantiate contract, two for getting state after execute the contract.

Run cargo-test in the terminal

If your output like below, everything is right:

running 1 test
test query::tests::test_query ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
Enter fullscreen mode Exit fullscreen mode

Sumary

I mentioned all entry points of the smart contract, wrote logic attach test case for our logic of smart contract.
Next part, I will build and deploy our contract to testnet network.
Thanks for reading and have a good day!

Top comments (0)