Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new cosmwasm doc #1968

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
40 changes: 16 additions & 24 deletions docs/CAPABILITIES.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
# Capabilities

Capabilities are a mechanism to negotiate functionality between a contract and
an environment (i.e. the chain that embeds cosmwasm-vm/[wasmvm]) in a very
primitive way. The contract defines required capabilities. The environment
defines it's capabilities. If the required capabilities are all available, the
contract can be used. Doing this check when the contract is first stored ensures
missing capabilities are detected early and not when a user tries to execute a
certain code path.

## Origin and Disambiguation

Before August 2022, we had two types of "features": app level features in the
CosmWasm VM and Cargo's build system features. In order to avoid the confusion,
the former have been renamed to capabilities.

Capabilities can be implemented in any language that compiles to Wasm whereas
features are Rust build system specific.

## Required capabilities

The contract defines required capabilities using marker export functions that
take no arguments and return no value. The name of the export needs to start
with "requires\_" followed by the name of the capability.
# Overview
**Capabilities** in CosmosWasm are a fundamental concept, designed to facilitate the interaction between a smart contract and its operational environment (i.e., the blockchain implementing the cosmwasm-vm or [wasmvm]). This mechanism operates by matching the capabilities required by a contract with those offered by the environment.

# The Essence of Capabilities
**Purpose:** They serve as a negotiation tool, ensuring that a contract only operates in an environment where all its necessary functionalities are present.
**Early Detection:** By verifying capabilities when a contract is first stored, any discrepancies or missing capabilities are identified early. This preemptive approach prevents potential runtime failures during execution.

# Historical Context: Origin and Disambiguation
**Prior to August 2022:** The term "features" was used ambiguously to describe both app-level features in the CosmWasm VM and features in Cargo's build system.
+**Redefinition:** To mitigate this confusion, app-level features in the CosmWasm VM were renamed to "capabilities," distinguishing them from Cargo's build system features.
+**Language Independence:** Unlike Rust-specific features, capabilities can be implemented in any language that compiles to Wasm, broadening their applicability.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved

# Defining Required Capabilities
## Implementation
**Marker Export Functions:** Contracts specify required capabilities using these functions, which have no arguments and return no value.
**Naming Convention:** The export name begins with "requires\_" followed by the capability name, establishing a clear and standardized method for declaration.

An example of such markers in cosmwasm-std are those:

Expand Down
49 changes: 24 additions & 25 deletions docs/STORAGE_KEYS.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
# Storage keys

CosmWasm provides a generic key value store to contract developers via the
`Storage` trait. This is powerful but the nature of low level byte operations
makes it hard to use for high level storage types. In this document we discuss
the foundations of storage key composition all the way up to cw-storage-plus.

In a simple world, all you need is a `&[u8]` key which you can get e.g. using
`&17u64.to_be_bytes()`. This is an 8 bytes key with an encoded integer. But if
you have multiple data types in your contract, you want to prefix those keys in
order to avoid collisions. A simple concatenation is not sufficient because you
want to avoid collisions when part of the prefixes and part of the key overlap.
E.g. `b"keya" | b"x"` and `b"key" | b"ax"` (`|` denotes concatenation) must not
have the same binary representation.
CosmWasm introduces a versatile key-value store accessible to contract developers
through the `Storage` trait. This low-level byte operation-based system, while powerful,
can be challenging for managing high-level storage types. This documentation explores
the evolution of storage key composition in CosmWasm, leading up to the current
implementation in cw-storage-plus.

# The Challenge of Key Composition

The fundamental requirement for storage keys in CosmWasm is a `&[u8]` key, which
can be derived from basic types like integers (e.g., `&17u64.to_be_bytes()`).
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
However, when handling various data types within a contract, it's crucial to
use prefixed keys to prevent data collisions.
Simple concatenation of keys is insufficient due to potential overlap issues.
For instance, `b"keya" | b"x"` and `b"key" | b"ax"` should not yield the same binary representation, where | denotes concatenation.

# Evolution of Key Namespacing

In the early days, multiple approaches of key namespacing were discussed and
were documented here: https://github.com/webmaster128/key-namespacing. The "0x00
Expand Down Expand Up @@ -39,12 +43,11 @@ pub fn to_length_prefixed_nested(namespaces: &[&[u8]]) -> Vec<u8>
fn concat(namespace: &[u8], key: &[u8]) -> Vec<u8>
```

With the emerging cw-storage-plus we see two additions to that approach:
# Transition to `cw-storage-plus`
With the introduction of cw-storage-plus, there were significant enhancements:

1. Manually creating the namespace and concatenating it with `concat` makes no
sense anymore. Instead `namespace` and `key` are always provided and a
composed database key is created.
2. Using a multi component namespace becomes the norm.
1. **Simplified Key Composition:** The manual creation of namespaces followed by concatenation using concat was replaced by a more integrated approach, where namespace and key are provided together to create a composed database key.
2. **Multi-component Namespaces:** Using multiple components in a namespace became commonplace.

This led to the following addition in cw-storage-plus:

Expand All @@ -68,14 +71,10 @@ With the deprecation if cosmwasm-storage and the adoption of the system in
cw-storage-plus, it is time to do a few changes to the Length-prefixed keys
standard, without breaking existing users.

1. Remove the single component `to_length_prefixed` implementation and fully
commit to the multi-component version. This shifts focus from the recursive
implementation to the compatible iterative implementation.
2. Rename "namespaces" to just "namespace" and let one namespace have multiple
components.
3. Adopt the combined namespace + key encoder `namespaces_with_key` from
cw-storage-plus.
4. Add a decomposition implementation
1. **Removal of Single Component Implementation:** The `to_length_prefixed` single-component version will be deprecated in favor of the multi-component `to_length_prefixed_nested` approach.
2. **Terminology Adjustment:** The term "namespaces" will be simplified to "namespace", encompassing multiple components.
3. **Adoption of Combined Encoder:** The `namespaces_with_key` function from `cw-storage-plus` will be the standard for key encoding.
4. **Decomposition Feature:** Introduction of a feature to decompose keys for enhanced flexibility.

Given the importance of Length-prefixed keys for the entire CosmWasm ecosystem,
those implementations should be maintained in cosmwasm-std. The generic approach
Expand Down
3 changes: 2 additions & 1 deletion packages/std/src/addresses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ impl fmt::Display for CanonicalAddr {
Ok(())
}
}

/// Errors related to the instantiation of contracts and generation of addresses.
/// Ensures the integrity and validity of newly created contracts.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum Instantiate2AddressError {
/// Checksum must be 32 bytes
Expand Down
4 changes: 2 additions & 2 deletions packages/std/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ pub struct OwnedDeps<S: Storage, A: Api, Q: Querier, C: CustomQuery = Empty> {
pub querier: Q,
pub custom_query_type: PhantomData<C>,
}

/// A mutable version of `Deps` that allows changes to the dependencies.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to have a doc comment here. I think we can be a bit more specific:

Suggested change
/// A mutable version of `Deps` that allows changes to the dependencies.
/// A mutable version of `Deps` that allows writing to storage.

pub struct DepsMut<'a, C: CustomQuery = Empty> {
pub storage: &'a mut dyn Storage,
pub api: &'a dyn Api,
pub querier: QuerierWrapper<'a, C>,
}

/// Represents dependencies required by a contract for execution, like storage and API access.
#[derive(Clone)]
pub struct Deps<'a, C: CustomQuery = Empty> {
pub storage: &'a dyn Storage,
Expand Down
3 changes: 2 additions & 1 deletion packages/std/src/errors/recover_pubkey_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use cosmwasm_crypto::CryptoError;

use super::BT;
use thiserror::Error;

/// Errors encountered during the recovery of a public key.
/// Typically arises from operations involving signatures or encrypted data.
#[derive(Error, Debug)]
pub enum RecoverPubkeyError {
#[error("Invalid hash format")]
Expand Down
33 changes: 19 additions & 14 deletions packages/std/src/errors/std_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,13 +393,13 @@ impl From<DivideByZeroError> for StdError {
}
}

/// The return type for init, execute and query. Since the error type cannot be serialized to JSON,
/// this is only available within the contract and its unit tests.
///
/// The prefix "Std" means "the standard result within the standard library". This is not the only
/// result/error type in cosmwasm-std.
/// `StdResult` is typically used in scenarios where a function within the contract needs to return a result or indicate an error
/// that is specific to the contract's internal operations. Since the error component of `StdResult` is not meant for JSON serialization,
/// it should be used with caution when designing functions that interact with external systems or data formats.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
pub type StdResult<T> = core::result::Result<T, StdError>;

/// Indicates operations that are prone to overflow.
/// Used to mark numerical operations where overflow checks are necessary.
enum OverflowOperation {
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Error, Debug, PartialEq, Eq)]
pub enum OverflowOperation {
Add,
Expand All @@ -415,7 +415,7 @@ impl fmt::Display for OverflowOperation {
write!(f, "{self:?}")
}
}

///An error struct used when a numeric operation results in an overflow.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: In general, we use a leading space for doc comments

#[derive(Error, Debug, PartialEq, Eq)]
#[error("Cannot {operation} with given operands")]
pub struct OverflowError {
Expand Down Expand Up @@ -449,7 +449,7 @@ impl ConversionOverflowError {
}
}
}

///An error struct used when a division operation in a contract attempts to divide by zero.
#[derive(Error, Debug, Default, PartialEq, Eq)]
#[error("Cannot divide by zero")]
pub struct DivideByZeroError;
Expand All @@ -468,7 +468,8 @@ pub enum DivisionError {
#[error("Overflow in division")]
Overflow,
}

/// Errors that occur when multiplying a value by a ratio in a checked manner.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
/// Ensures precision and overflow safety in the operation.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Error, Debug, PartialEq, Eq)]
pub enum CheckedMultiplyFractionError {
#[error("{0}")]
Expand All @@ -480,7 +481,8 @@ pub enum CheckedMultiplyFractionError {
#[error("{0}")]
Overflow(#[from] OverflowError),
}

/// Represents errors during safe multiplication of a number by a fraction.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
/// Ensures accuracy and overflow prevention in calculations.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Error, Debug, PartialEq, Eq)]
pub enum CheckedMultiplyRatioError {
#[error("Denominator must not be zero")]
Expand All @@ -489,7 +491,8 @@ pub enum CheckedMultiplyRatioError {
#[error("Multiplication overflow")]
Overflow,
}

/// Errors that occur when safely converting from a ratio type.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not really about a ratio type. It's returned for example here and also for all the versions of that functions for the different types of decimals.
So, really these are errors that occur when creating a decimal type from a ratio of two numbers.

/// Ensures mathematical accuracy and prevents potential overflow issues.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Error, Debug, PartialEq, Eq)]
pub enum CheckedFromRatioError {
#[error("Denominator must not be zero")]
Expand All @@ -506,7 +509,8 @@ pub struct RoundUpOverflowError;
#[derive(Error, Debug, PartialEq, Eq)]
#[error("Round down operation failed because of overflow")]
pub struct RoundDownOverflowError;

/// General errors related to operations with coins,
/// such as invalid amounts or unsupported denominations.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum CoinsError {
#[error("Duplicate denom")]
Expand All @@ -518,7 +522,8 @@ impl From<CoinsError> for StdError {
Self::generic_err(format!("Creating Coins: {value}"))
}
}

/// Errors encountered when parsing coin values from strings.
/// Ensures that coin strings are in the correct format and valid.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum CoinFromStrError {
#[error("Missing denominator")]
Expand Down Expand Up @@ -786,4 +791,4 @@ mod tests {
err => panic!("Unexpected error: {err:?}"),
}
}
}
}
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions packages/std/src/hex_binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{Binary, StdError, StdResult};
/// This is similar to `cosmwasm_std::Binary` but uses hex.
/// See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.
#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
///A wrapper around a vector (Vec) for hex-encoded binary data, supporting encoding and decoding operations.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There already is a doc string above the #[derive(...)]. I'd say we use yours as the first paragraph, but keep the reference to the message types and Binary type.

pub struct HexBinary(#[schemars(with = "String")] Vec<u8>);

impl HexBinary {
Expand Down
25 changes: 15 additions & 10 deletions packages/std/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use crate::results::{Attribute, CosmosMsg, Empty, Event, SubMsg};
use crate::serde::to_json_binary;
use crate::timestamp::Timestamp;

/// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts
/// (contracts that directly speak the IBC protocol via 6 entry points)
/// Messages pertaining to the IBC lifecycle, specifically for contracts with IBC capabilities.
/// Manages cross-chain communications and other IBC protocol interactions.
enum IbcMsg {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is also doubled

#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -50,7 +51,7 @@ pub enum IbcMsg {
/// Port is auto-assigned to the contract's IBC port
CloseChannel { channel_id: String },
}

///Details about an IBC endpoint, including its port and channel information.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct IbcEndpoint {
pub port_id: String,
Expand Down Expand Up @@ -147,9 +148,9 @@ impl IbcChannel {
}
}

/// IbcOrder defines if a channel is ORDERED or UNORDERED
/// Enumerates the ordering of messages in an IBC channel, such as ORDERED or UNORDERED.
/// Based on the IBC specifications for message sequencing.
/// Values come from https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/core/channel/v1/channel.proto#L69-L80
/// Naming comes from the protobuf files and go translations.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum IbcOrder {
#[serde(rename = "ORDER_UNORDERED")]
Expand Down Expand Up @@ -192,7 +193,7 @@ impl Ord for IbcTimeoutBlock {
}
}
}

///Struct representing an IBC packet, which contains data transferred across different blockchains.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[non_exhaustive]
pub struct IbcPacket {
Expand Down Expand Up @@ -225,7 +226,7 @@ impl IbcPacket {
}
}
}

///Represents an acknowledgement message in the IBC protocol.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[non_exhaustive]
pub struct IbcAcknowledgement {
Expand All @@ -246,7 +247,8 @@ impl IbcAcknowledgement {
}
}

/// The message that is passed into `ibc_channel_open`
/// Message used to establish a connection in an IBC channel.
/// Initiates the setup for cross-chain or inter-module communication.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IbcChannelOpenMsg {
Expand Down Expand Up @@ -304,12 +306,14 @@ impl From<IbcChannelOpenMsg> for IbcChannel {
pub type IbcChannelOpenResponse = Option<Ibc3ChannelOpenResponse>;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
///A response format for IBC channel open queries, providing details about the channel's status.
pub struct Ibc3ChannelOpenResponse {
/// We can set the channel version to a different one than we were called with
pub version: String,
}

/// The message that is passed into `ibc_channel_connect`
/// Message used to establish a connection in an IBC channel.
/// Initiates the setup for cross-chain or inter-module communication.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IbcChannelConnectMsg {
Expand Down Expand Up @@ -411,7 +415,7 @@ impl IbcPacketReceiveMsg {
}
}

/// The message that is passed into `ibc_packet_ack`
/// Message format used when acknowledging the receipt of an IBC packet.
costa2400 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[non_exhaustive]
pub struct IbcPacketAckMsg {
Expand Down Expand Up @@ -456,6 +460,7 @@ impl IbcPacketTimeoutMsg {
/// or that cannot redispatch messages (like the handshake callbacks)
/// will use other Response types
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
///A general response structure for IBC handler operations, used when a specific response format isn't required.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also already has a doc comment above the #[derive(...)]

#[non_exhaustive]
pub struct IbcBasicResponse<T = Empty> {
/// Optional list of messages to pass. These will be executed in order.
Expand Down
3 changes: 2 additions & 1 deletion packages/std/src/math/fraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ impl<T: Copy + From<u8> + PartialEq> Fraction<T> for (T, T) {
}
}
}

//Adds a function to a type that allows you to multiply instances of that type by a fraction.
//It's useful for calculations involving fractional multiplication.
#[macro_export]
macro_rules! impl_mul_fraction {
($Uint:ident) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/std/src/math/signed_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use super::Int128;
pub struct SignedDecimal(#[schemars(with = "String")] Int128);

forward_ref_partial_eq!(SignedDecimal, SignedDecimal);

///Similar to `SignedDecimal256RangeExceeded`, but for standard `SignedDecimal` operations.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use brackets here, we can link to the type, so it's easier to navigate:

Suggested change
///Similar to `SignedDecimal256RangeExceeded`, but for standard `SignedDecimal` operations.
/// Similar to [`crate::SignedDecimal256RangeExceeded`], but for standard `SignedDecimal` operations.

#[derive(Error, Debug, PartialEq, Eq)]
#[error("SignedDecimal range exceeded")]
pub struct SignedDecimalRangeExceeded;
Expand Down
2 changes: 1 addition & 1 deletion packages/std/src/math/signed_decimal_256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use super::Int256;
pub struct SignedDecimal256(#[schemars(with = "String")] Int256);

forward_ref_partial_eq!(SignedDecimal256, SignedDecimal256);

/// Indicates an error when a SignedDecimal256 operation exceeds its range.
#[derive(Error, Debug, PartialEq, Eq)]
#[error("SignedDecimal256 range exceeded")]
pub struct SignedDecimal256RangeExceeded;
Expand Down