- Docs
- Smart Contracts
- Querying contract state
Querying contract state
In CosmWasm, querying a contract's state is a fundamental aspect of interacting with smart contracts, whether as an external client or from within another contract. This document explores the two primary types of queries: raw and custom and examines the semantics of querying via an external client versus an internal client (another contract). We will also address design and security considerations, particularly when executing queries from one contract to another.
Raw queries
Raw queries are the most straightforward type of query, providing direct access to the key-value store of the contract's state. If the caller (either an external client or another contract) knows the exact binary key used in the contract's storage, they can retrieve the corresponding raw binary value.
Advantages and limitations
- Simplicity: Raw queries are easy to implement and are universally applicable since they bypass the virtual machine (VM) and directly access the contract's storage. This means they require no special support from the CosmWasm contract.
- Direct Access: The query_raw function is exposed to all callers, both external and internal, making the entire contract state visible to anyone with knowledge of the storage keys.
- Knowledge Dependency: The main limitation is that raw queries require intimate knowledge of the contract's implementation, making them less flexible and more prone to errors if the contract's internal structure changes.
Custom queries
Custom queries provide a more flexible and structured way to interact with a contract's state, abstracting away the implementation details. Instead of requiring knowledge of the raw storage keys, custom queries use a defined interface to access contract data.
Advantages of custom queries
- Interface-Based Access: Custom queries allow contracts to expose specific query endpoints that provide read-only access to their internal data. These endpoints can perform calculations and return structured responses, making it easier to interact with complex contracts.
- Standardization: By defining standard interfaces, such as those for CW20 tokens, contracts can be designed to interact with each other without needing to understand their internal workings. This promotes interoperability and composability within the Cosmos ecosystem.
Implementation details
Custom queries are implemented via the query_custom function, which is available to both external and internal callers. The data format for both the query and the response is flexible and defined by the contract developer. This flexibility requires thorough documentation in the contract's public schema, alongside ExecuteMsg and InstantiateMsg.
Gas considerations
Custom queries can be more resource-intensive than raw queries, as they may involve complex calculations or data aggregation. To prevent potential abuse, especially in external queries, a gas limit is enforced. This limit ensures that even if a query is resource-intensive, it will not lead to denial-of-service (DoS) attacks or excessive resource consumption.
External queries
External queries are the primary method for interacting with a blockchain's state from web applications, CLI clients, and other external tools. These queries are routed through Tendermint RPC, which then calls abci_query in the Cosmos SDK to delegate the task to the appropriate module.
Security and performance considerations
To protect public RPC nodes from abuse, a fixed gas limit is applied to all query_custom transactions initiated externally. This gas limit is not used to charge fees but rather to prevent excessive resource consumption.
- Configurable Limits: The gas limit for query_custom calls can be configured in a node's app-specific configuration file, allowing node operators to adjust the limit based on the node's intended use (e.g., public vs. archival nodes).
- Snapshot State: The abci_query function does not access the current "in-progress" state of the modules. Instead, it queries a read-only snapshot of the state from the last committed block, ensuring consistency and preventing data corruption during ongoing transactions.
Internal queries
While most interactions between contracts can be handled by sending messages, there are cases where synchronous querying of another contract's state is necessary. For example, resolving a name to an address or checking an account's status before performing an action.
Design and security considerations
Internal queries, whether query_raw or query_custom, pose a unique challenge to the actor model's principles, as they allow a contract to access another contract's state. However, CosmWasm mitigates potential security risks through careful design:
- Read-Only Access: The Querier in CosmWasm provides read-only access to the state snapshot taken just before the execution of the current message. This snapshot ensures that both the executing contract and the queried contract access consistent data without altering the state.
- Concurrency and Reentrancy Protection: By using Rust's borrowing rules, CosmWasm ensures that all writes during contract execution are confined to a cache, which is only flushed to the state upon successful completion. This design prevents reentrancy attacks and maintains the integrity of contract execution.
Gas usage
Internal queries are performed as part of a transaction, which already enforces a strict gas limit. All storage reads and data processing within a query are deducted from the transaction's gas meter, ensuring that even complex queries do not exceed the allocated resources.