This site requires Javascript to be enabled.

Query

Querying in CosmWasm is the process of extracting data from the contract's state without modifying it. This read-only operation is essential for accessing and analyzing the state information managed by the contract. Queries can be performed either externally (via APIs or CLI tools) or internally within other smart contracts.

Typically, the available query messages are defined in the msg.rs or query.rs files, depending on how the contract author has organized the code. These files outline the query interface, which allows external actors to request specific data from the contract.

For more detailed information on how querying works in CosmWasm, refer to the Querying Contract State guide.

Understanding query messages

Query messages are designed to access the contract's data store in read-only mode. They retrieve data, potentially perform some computation or processing on that data, and return the result to the requester.

Structure of query messages

Query messages are typically defined as variants of a QueryMsg enum. This enum specifies the different types of queries that the contract supports. Here’s an example:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum QueryMsg {    // ResolveRecord returns the current address that the name resolves to    ResolveRecord { name: String },    // Config returns the contract's configuration    Config {},}

In this example, the QueryMsg enum defines two query types:

  • ResolveRecord: Queries the contract to resolve a name to an address.
  • Config: Retrieves the contract’s configuration settings.

Processing queries in the contract

Once a query message is received, it is handled by the contract’s query function. This function matches the incoming QueryMsg variant to the corresponding logic within the contract. Here's an example of how this might look:

#[cfg_attr(not(feature = "library"), entry_point)]pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {    match msg {        QueryMsg::ResolveRecord { name } => query_resolver(deps, env, name),        QueryMsg::Config {} => to_binary(&config_read(deps.storage).load()?),    }}

Explanation

  • Deps and Env: The deps argument provides access to the contract's dependencies, including the storage, API, and querier. The env argument provides environmental information, such as the block height and time.
  • Query Routing: The match statement routes the incoming query message to the appropriate handler function:
    • query_resolver(deps, env, name) is called to resolve a name to an address.
    • to_binary(&config_read(deps.storage).load()?) retrieves and serializes the contract's configuration settings into a binary format.

Example query handlers

The query handlers (query_resolver and config_read) are responsible for executing the query logic and returning the data. Here’s an example of what these handlers might look like:

pub fn query_resolver(deps: Deps, _env: Env, name: String) -> StdResult<Binary> {    let address = deps.storage.get(name.as_bytes()).ok_or_else(|| {        StdError::not_found("Record")    })?;    to_binary(&address)}pub fn config_read(storage: &dyn Storage) -> ReadonlySingleton<Config> {    singleton_read(storage, CONFIG_KEY)}
  • query_resolver: Retrieves the address associated with a given name from storage. If the name does not exist, it returns a "not found" error.
  • config_read: Reads the contract’s configuration from storage.

Best practices for querying

  1. Optimize Query Performance: Keep query handlers lightweight to minimize gas usage. Avoid complex computations or heavy data processing within queries.
  2. Security Considerations: Validate inputs and handle errors gracefully to prevent unauthorized data access or potential abuse. Ensure that sensitive information is not exposed through queries.
  3. Consistent Data Formatting: Use serialization (e.g., to_binary) to ensure consistent data formatting across queries. This helps maintain compatibility with external clients and other contracts.
  4. Documentation and Testing: Clearly document the available query messages and test them thoroughly to ensure reliability and correctness.