Skip to content

Commit

Permalink
Governance module documentation (#236)
Browse files Browse the repository at this point in the history
  • Loading branch information
DariuszDepta authored Jan 24, 2025
2 parents 51fef91 + 858128d commit 1b4c302
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 14 deletions.
43 changes: 42 additions & 1 deletion src/pages/cw-multi-test/app-builder.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
tags: ["multitest", "AppBuilder"]
---

import { Callout } from "nextra/components";

[AppBuilder]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html
[Builder Pattern]: https://en.wikipedia.org/wiki/Builder_pattern
[BlockInfo]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.BlockInfo.html
[with_block]:
https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_block
[with_gov]:
https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_gov
[build]: #build
[GovAcceptingModule]:
https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovAcceptingModule.html
[GovFailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html

# `AppBuilder`

Expand Down Expand Up @@ -103,7 +110,41 @@ with any other `with_*` methods to configure a custom starting block.

## `with_gov`

(WIP)
The [`with_gov{:rust}`][with_gov] function allows you to customize the governance module of your
test blockchain environment. This function enables you to override the default governance module
with a custom implementation that suits your specific testing needs. Currently, **`MultiTest`**
provides two minimal implementations of the governance module that do not attempt to replicate real
blockchain behavior: [`GovAcceptingModule{:rust}`][GovAcceptingModule] and
[`GovFailingModule{:rust}`][GovFailingModule].

To use a built-in governance module that accepts all messages, initialize the chain like shown below
(line 4):

```rust showLineNumbers copy {15} /with_gov/ /GovAcceptingModule/
use cw_multi_test::{no_init, AppBuilder, GovAcceptingModule};

let app = AppBuilder::default()
.with_gov(GovAcceptingModule::new())
.build(no_init);
```

When processing governance messages in your tests should always fail, initialize the chain like in
the following code snippet (line 4):

```rust showLineNumbers copy /with_gov/ /GovFailingModule/
use cw_multi_test::{no_init, AppBuilder, GovFailingModule};

let app = AppBuilder::default()
.with_gov(GovFailingModule::new())
.build(no_init);
```

<Callout>
Note that [`GovFailingModule{:rust}`][GovFailingModule] is the default one in `App{:rust}`.
</Callout>

You can find more usage examples of the built-in governance modules in the
[Governance](./governance) chapter.

## `with_ibc`

Expand Down
26 changes: 13 additions & 13 deletions src/pages/cw-multi-test/features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ you can provide your own, using `AppBuilder`'s function listed in **AppBuilder&n
column. Names of **`MultiTest`** feature flags required to enable specific functionality are shown
in the column **Feature&nbsp;flag**.

| Feature | Default<br/>implementation | Feature<br/>flag | AppBuilder<br/>constructor | Functionality |
| ---------------- | ---------------------------------------------------------------------------------------------------------------- | :--------------: | ---------------------------------------------------- | -------------------------------------------------- |
| [Blocks](blocks) | [`mock_env().block{:rust}`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/fn.mock_env.html) | | [`with_block`](app-builder#with_block) | Operations on blocks. |
| API | [`MockApi{:rust}`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html) | | [`with_api`](app-builder#with_api) | Access to CosmWasm API. |
| Storage | [`MockStorage{:rust}`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/type.MockStorage.html) | | [`with_storage`](app-builder#with_storage) | Access to storage. |
| Bank | [`BankKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.BankKeeper.html) | | [`with_bank`](app-builder#with_bank) | Interactions with **Bank** module. |
| Staking | [`StakeKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.StakeKeeper.html) | `staking` | [`with_staking`](app-builder#with_staking) | Interactions with **Staking** module. |
| Distribution | [`DistributionKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.DistributionKeeper.html) | `staking` | [`with_distribution`](app-builder#with_distribution) | Interactions with **Distribution** module. |
| Governance | [`GovFailingModule{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html) | | [`with_gov`](app-builder#with_gov) | Interactions with **Governance** module. |
| Stargate | [`StargateFailing{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.StargateFailing.html) | `stargate` | [`with_stargate`](app-builder#with_stargate) | Operations using `Stargate` and/or `Any` messages. |
| Wasm | [`WasmKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.WasmKeeper.html) | | [`with_wasm`](app-builder#with_wasm) | Interactions with **Wasm** module. |
| Custom | [`FailingModule{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.FailingModule.html) | | [`new_custom`](app-builder#new_custom) | Operations using custom module. |
| IBC | [`IbcFailingModule{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/type.IbcFailingModule.html) | `stargate` | [`with_ibc`](app-builder#with_ibc) | Inter-blockchain communication operations. |
| Feature | Default<br/>implementation | Feature<br/>flag | AppBuilder<br/>constructor | Functionality |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------- | :--------------: | ---------------------------------------------------- | -------------------------------------------------- |
| [Blocks](blocks) | [`mock_env().block{:rust}`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/fn.mock_env.html) | | [`with_block`](app-builder#with_block) | Operations on blocks. |
| API | [`MockApi{:rust}`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html) | | [`with_api`](app-builder#with_api) | Access to CosmWasm API. |
| Storage | [`MockStorage{:rust}`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/type.MockStorage.html) | | [`with_storage`](app-builder#with_storage) | Access to storage. |
| Bank | [`BankKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.BankKeeper.html) | | [`with_bank`](app-builder#with_bank) | Interactions with **Bank** module. |
| Staking | [`StakeKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.StakeKeeper.html) | `staking` | [`with_staking`](app-builder#with_staking) | Interactions with **Staking** module. |
| Distribution | [`DistributionKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.DistributionKeeper.html) | `staking` | [`with_distribution`](app-builder#with_distribution) | Interactions with **Distribution** module. |
| [Governance](governance) | [`GovFailingModule{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html) | | [`with_gov`](app-builder#with_gov) | Interactions with **Governance** module. |
| Stargate | [`StargateFailing{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.StargateFailing.html) | `stargate` | [`with_stargate`](app-builder#with_stargate) | Operations using `Stargate` and/or `Any` messages. |
| Wasm | [`WasmKeeper{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.WasmKeeper.html) | | [`with_wasm`](app-builder#with_wasm) | Interactions with **Wasm** module. |
| Custom | [`FailingModule{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.FailingModule.html) | | [`new_custom`](app-builder#new_custom) | Operations using custom module. |
| IBC | [`IbcFailingModule{:rust}`](https://docs.rs/cw-multi-test/latest/cw_multi_test/type.IbcFailingModule.html) | `stargate` | [`with_ibc`](app-builder#with_ibc) | Inter-blockchain communication operations. |

## Feature flags summary

Expand Down
200 changes: 200 additions & 0 deletions src/pages/cw-multi-test/governance.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
---
tags: ["multitest", "governance"]
---

[GovAcceptingModule]:
https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovAcceptingModule.html
[GovFailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html

# Governance

**`MultiTest`** provides two minimal implementations of the governance module that **do not**
replicate the real blockchain behavior: [`GovAcceptingModule{:rust}`][GovAcceptingModule] and
[`GovFailingModule{:rust}`][GovFailingModule]. The default chain configuration is using
[`GovFailingModule{:rust}`][GovFailingModule].

The following sections provide examples of how to initialize a specific governance module and how to
execute governance messages in tests.

## Default governance module

Currently, in **`MultiTest`**, the default governance module is
[`GovFailingModule{:rust}`][GovFailingModule], and no additional configuration is required to use
it.

### `GovMsg::Vote`

```rust showLineNumbers {5,20} copy /GovMsg::Vote/
use cosmwasm_std::{GovMsg, VoteOption};
use cw_multi_test::{no_init, AppBuilder, Executor, IntoAddr};

// Build the application with default (always failing) governance module.
let mut app = AppBuilder::default().build(no_init);

// Prepare sender address.
let sender_addr = "sender".into_addr();

// Prepare message for vote.
let vote_msg = GovMsg::Vote {
proposal_id: 1,
option: VoteOption::Yes,
};

// Execute vote governance message.
let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();

// Always an error is returned.
assert!(response.to_string().starts_with("Unexpected exec msg Vote"));
```

### `GovMsg::VoteWeighted`

```rust showLineNumbers {5,23} copy /GovMsg::VoteWeighted/
use cosmwasm_std::{Decimal, GovMsg, Uint128, VoteOption, WeightedVoteOption};
use cw_multi_test::{no_init, AppBuilder, Executor, IntoAddr};

// Build the application with default (always failing) governance module.
let mut app = AppBuilder::default().build(no_init);

// Prepare sender address.
let sender_addr = "sender".into_addr();

// Prepare message for weighted vote.
let vote_msg = GovMsg::VoteWeighted {
proposal_id: 1,
options: vec![WeightedVoteOption {
option: VoteOption::Yes,
weight: Decimal::new(Uint128::new(12)),
}],
};

// Execute weighted vote governance message.
let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();

// Always an error is returned.
assert!(response.to_string().starts_with("Unexpected exec msg VoteWeighted"));
```

## Failing governance module

Executing governance messages using [`GovFailingModule{:rust}`][GovFailingModule] always returns an
error.

### `GovMsg::Vote`

```rust showLineNumbers {6,22} copy /GovMsg::Vote/
use cosmwasm_std::{GovMsg, VoteOption};
use cw_multi_test::{no_init, AppBuilder, Executor, GovFailingModule, IntoAddr};

// Build the application with always failing governance module.
let mut app = AppBuilder::default()
.with_gov(GovFailingModule::new())
.build(no_init);

// Prepare sender address.
let sender_addr = "sender".into_addr();

// Prepare message for vote.
let vote_msg = GovMsg::Vote {
proposal_id: 1,
option: VoteOption::Yes,
};

// Execute vote governance message.
let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();

// Always an error is returned.
assert!(response.to_string().starts_with("Unexpected exec msg Vote"));
```

### `GovMsg::VoteWeighted`

```rust showLineNumbers {6,25} copy /GovMsg::VoteWeighted/
use cosmwasm_std::{Decimal, GovMsg, Uint128, VoteOption, WeightedVoteOption};
use cw_multi_test::{no_init, AppBuilder, Executor, GovFailingModule, IntoAddr};

// Build the application with always failing governance module.
let mut app = AppBuilder::default()
.with_gov(GovFailingModule::new())
.build(no_init);

// Prepare sender address.
let sender_addr = "sender".into_addr();

// Prepare message for weighted vote.
let vote_msg = GovMsg::VoteWeighted {
proposal_id: 1,
options: vec![WeightedVoteOption {
option: VoteOption::Yes,
weight: Decimal::new(Uint128::new(12)),
}],
};

// Execute weighted vote governance message.
let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();

// Always an error is returned.
assert!(response.to_string().starts_with("Unexpected exec msg VoteWeighted"));
```

## Accepting governance module

Executing governance messages using [`GovAcceptingModule{:rust}`][GovAcceptingModule] always
succeeds, but the returned data is empty.

### `GovMsg::Vote`

```rust showLineNumbers {6,22} copy /GovMsg::Vote/
use cosmwasm_std::{GovMsg, VoteOption};
use cw_multi_test::{no_init, AppBuilder, Executor, GovAcceptingModule, IntoAddr};

// Build the application with always failing governance module.
let mut app = AppBuilder::default()
.with_gov(GovAcceptingModule::new())
.build(no_init);

// Prepare sender address.
let sender_addr = "sender".into_addr();

// Prepare message for vote.
let vote_msg = GovMsg::Vote {
proposal_id: 1,
option: VoteOption::Yes,
};

// Execute vote governance message.
let response = app.execute(sender_addr, vote_msg.into()).unwrap();

// Always empty data is returned.
assert_eq!(None, response.data);
```

### `GovMsg::VoteWeighted`

```rust showLineNumbers {6,25} copy /GovMsg::VoteWeighted/
use cosmwasm_std::{Decimal, GovMsg, Uint128, VoteOption, WeightedVoteOption};
use cw_multi_test::{no_init, AppBuilder, Executor, GovAcceptingModule, IntoAddr};

// Build the application with always failing governance module.
let mut app = AppBuilder::default()
.with_gov(GovAcceptingModule::new())
.build(no_init);

// Prepare sender address.
let sender_addr = "sender".into_addr();

// Prepare message for weighted vote.
let vote_msg = GovMsg::VoteWeighted {
proposal_id: 1,
options: vec![WeightedVoteOption {
option: VoteOption::Yes,
weight: Decimal::new(Uint128::new(12)),
}],
};

// Execute weighted vote governance message.
let response = app.execute(sender_addr, vote_msg.into()).unwrap();

// Always empty data is returned.
assert_eq!(None, response.data);
```

0 comments on commit 1b4c302

Please sign in to comment.