Skip to content

Commit 085dac8

Browse files
committed
Added Blocks chapter.
1 parent 9e7f55c commit 085dac8

File tree

3 files changed

+232
-8
lines changed

3 files changed

+232
-8
lines changed

docs/multi-test/blocks.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
2+
# Blocks
3+
4+
There are several cases when testing CosmWasm smart contracts requires simulating delays on the
5+
blockchain, like:
6+
7+
- staking and unstaking processes,
8+
- governance voting periods,
9+
- validator set changes,
10+
- token vesting schedules,
11+
- incentive distribution, or
12+
- IBC packet timeouts.
13+
14+
## Operations on blocks
15+
16+
**MultiTest** provides several operations to initialize and update current block properties, such
17+
as height and timestamp, in order to test delays on the blockchain.
18+
19+
:::tip
20+
21+
Although it is possible to modify **only** the height or **only** the timestamp of the block in
22+
**MultiTest**, this is not feasible in a real-life blockchain and may lead to unpredictable test
23+
results that do not reflect the blockchain's real-life behavior.
24+
25+
:::
26+
27+
:::warning
28+
29+
Always increment the height **and** the timestamp of the block in tests.
30+
31+
:::
32+
33+
In the following chapters, you will find practical examples of several operations on blocks, such as
34+
block initialization and generating a new block.
35+
36+
## Initialization with the default block
37+
38+
In **MultiTest**, the chain is initialized with a default block that has the following properties:
39+
40+
- `height`: **12345**,
41+
- `time`: **1571797419879305533** (Wed Oct 23 2019 02:23:39 GMT+0000),
42+
- `chain_id`: **cosmos-testnet-14002**.
43+
44+
These properties constitute the [`BlockInfo`][BlockInfo] structure, which is defined in the
45+
CosmWasm library for representing block metadata. [`BlockInfo`][BlockInfo] can be retrieved
46+
at any point in a test by calling the [`block_info`][block_info] method provided by
47+
`App`.
48+
49+
The following example illustrates this case in detail.
50+
51+
```rust showLineNumbers {4,7,10,13,16}
52+
use cw_multi_test::App;
53+
54+
// create the default chain simulator
55+
let app = App::default();
56+
57+
// get the initial block properties
58+
let block = app.block_info();
59+
60+
// default block height is 12345
61+
assert_eq!(12345, block.height);
62+
63+
// default block timestamp is Wed Oct 23 2019 02:23:39 GMT+0000
64+
assert_eq!(1571797419879305533, block.time.nanos());
65+
66+
// default chain identifier is "cosmos-testnet-14002"
67+
assert_eq!("cosmos-testnet-14002", block.chain_id);
68+
```
69+
70+
In line 4, the chain is initialized and _started_ with the default settings by calling the function
71+
[`default`][app_default] on `App`. In line 7, the current block metadata (of type
72+
[`BlockInfo`][BlockInfo]) is retrieved and assigned to variable `block`. In the next
73+
few lines, the default values are checked:
74+
75+
- line 10: block `height` is `12345`,
76+
- line 13: block `time` is a Unix timestamp of value `1571797419879305533`, which is
77+
the numeric representation of `Wednesday, October 23, 2019 02:23:39 GMT`,
78+
- line 16: block `chain_id` has a default value `"cosmos-testnet-14002"`.
79+
80+
## Initialization with the custom block
81+
82+
Although the chain initialization with the default block may be suitable for most test cases, it is
83+
possible to initialize the chain with a custom [`BlockInfo`][BlockInfo] using the
84+
[`set_block`][set_block] method provided by `App`. The following example explains this
85+
case in detail.
86+
87+
```rust showLineNumbers {8-12}
88+
use cosmwasm_std::{BlockInfo, Timestamp};
89+
use cw_multi_test::App;
90+
91+
// create the default chain simulator
92+
let mut app = App::default();
93+
94+
// create and use a custom block
95+
app.set_block(BlockInfo {
96+
height: 1,
97+
time: Timestamp::from_seconds(1723627489),
98+
chain_id: "starship-testnet".to_string(),
99+
});
100+
101+
// get the custom block properties
102+
let block = app.block_info();
103+
104+
// now the block height is 1
105+
assert_eq!(1, block.height);
106+
107+
// now the block timestamp is Wed Aug 14 2024 09:24:49 GMT+0000
108+
assert_eq!(1723627489, block.time.seconds());
109+
110+
// now the chain identifier is "starship-testnet"
111+
assert_eq!("starship-testnet", block.chain_id);
112+
```
113+
114+
The chain is started with the default settings in line 5. Then in line 8, the
115+
[`set_block`][set_block] method is called with custom block properties provided as
116+
[`BlockInfo`][BlockInfo] structure. The current block metadata is retrieved in line 12 and in
117+
the next few lines the detailed values are checked:
118+
119+
- line 18: block `height` is now `1`,
120+
- line 21: new block `time` is a Unix timestamp of value `1723627489`, which is the
121+
numeric representation (in seconds) of `Wednesday, August 14, 2024 09:24:49 GMT`,
122+
- line 24: block `chain_id` has now a value `"starship-testnet"`.
123+
124+
This way, you can initialize the current block in tests to best suit your requirements.
125+
126+
:::info
127+
128+
You can also initialize the blockchain simulator with the custom block using [AppBuilder], as
129+
shown in this [example](app-builder#with_block).
130+
131+
:::
132+
133+
## Generating next block with the default step
134+
135+
To generate a new block in tests, you can use the [`update_block`][update_block] method
136+
provided by `App`. In the following example, [`update_block`][update_block] method
137+
takes a function [`next_block`][next_block] as an argument. [`next_block`][next_block]
138+
function - provided by **`MultiTest`** - increases the block height by `1` and advances the block
139+
time by `5` seconds, simulating the generation of a new block every `5` seconds in a real-life
140+
blockchain. The `chain_id` remains unchanged.
141+
142+
```rust showLineNumbers {7}
143+
use cw_multi_test::{next_block, App};
144+
145+
// create the default chain simulator
146+
let mut app = App::default();
147+
148+
// update the block by `generating` next block
149+
app.update_block(next_block);
150+
151+
// get the current block properties
152+
let block = app.block_info();
153+
154+
// now the block height is 1 after the initial value
155+
assert_eq!(12346, block.height);
156+
157+
// now the block timestamp is 5 seconds after the initial value
158+
// current value is: Wed Oct 23 2019 02:23:44 GMT+0000
159+
// initial value was: Wed Oct 23 2019 02:23:39 GMT+0000
160+
assert_eq!(1571797424879305533, block.time.nanos());
161+
162+
// chain identifier remains unchanged
163+
assert_eq!("cosmos-testnet-14002", block.chain_id);
164+
```
165+
166+
In line 7 the [`update_block`][update_block] method is called and in the next few lines the
167+
current block properties are checked. In line 10 the block metadata is retrieved and assigned to
168+
variable `block`. In line 13, we check if the block height has changed. The default block
169+
height is `12345`, and we check it against the value `12346`. As this assertion
170+
passes, you can see that the block height was indeed incremented by `1`. Similarly, the block's time
171+
is checked against the Unix timestamp, which is 5 seconds later than the default value:
172+
`1571797424879305533` - `1571797419879305533` = `5000000000` = 5 seconds.
173+
174+
## Generating next block with the custom step
175+
176+
Several events on the blockchain occur after a period longer than a few seconds. In such cases,
177+
incrementing the block time multiple times until the desired time is reached would be impractical.
178+
In **`MultiTest`**, it is possible to advance the block using a specific block height and time. To
179+
achieve this, pass a custom closure to the [`update_block`][update_block] method. This
180+
closure takes a mutable [`BlockInfo`][BlockInfo] structure as an argument and modifies its
181+
properties, as shown in the example below.
182+
183+
```rust showLineNumbers {7-10}
184+
use cw_multi_test::App;
185+
186+
// create the default chain simulator
187+
let mut app = App::default();
188+
189+
// 'generate' custom block
190+
app.update_block(|block| {
191+
block.time = block.time.plus_days(6);
192+
block.height += 10000;
193+
});
194+
195+
// get the block properties after updating
196+
let block = app.block_info();
197+
198+
// now the block height is 10000 after the initial value
199+
assert_eq!(22345, block.height);
200+
201+
// now the block timestamp is 6 days after the initial value
202+
// current value is: Wed Oct 23 2019 02:23:44 GMT+0000
203+
// initial value was: Tue Oct 29 2019 02:23:39 GMT+0000
204+
assert_eq!(1572315819879305533, block.time.nanos());
205+
206+
// chain identifier remains unchanged
207+
assert_eq!("cosmos-testnet-14002", block.chain_id);
208+
```
209+
210+
In line 4, the default block is initialized during the chain start. Then in line 7, the
211+
[`update_block`][update_block] method takes a custom closure as an argument. This closure
212+
increments the block height by **10000** and advances the block time by **6 days**. Similarly like
213+
in previous examples, the new block metadata is retrieved and the current properties are checked.
214+
The new block height should be `12345` + `10000` = `22345`. The new block time
215+
should be `1572315819879305533` -`1571797419879305533` = `518400000000000` =
216+
518400 seconds = 8640 minutes = 144 hours = **6 days**. The chain identifier remains unchanged.
217+
218+
[BlockInfo]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.BlockInfo.html
219+
[AppBuilder]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html
220+
[block_info]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.block_info
221+
[set_block]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.set_block
222+
[update_block]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.update_block
223+
[next_block]: https://docs.rs/cw-multi-test/latest/cw_multi_test/fn.next_block.html
224+
[app_default]: app#default

docs/multi-test/features.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ you can provide your own, using `AppBuilder`'s function listed in **AppBuilder&n
1515
column. Names of **MultiTest** feature flags required to enable specific functionality are shown
1616
in the column **Feature flag**.
1717

18-
| Feature | Default<br/>implementation | Feature<br/>flag | AppBuilder<br/>constructor | Functionality |
19-
|----------------|---------------------------------------------------|:----------------:|------------------------------------------------------|----------------------------------------------------|
18+
| Feature | Default<br/>implementation | Feature<br/>flag | AppBuilder<br/>constructor | Functionality |
19+
|----------------|--------------------------------------------|:----------------:|------------------------------------------------------|----------------------------------------------------|
2020
| [Blocks] | [`mock_env().block`][mock_env_block] | | [`with_block`](app-builder#with_block) | Operations on blocks. |
2121
| [Api] | [`MockApi`][MockApi] | | [`with_api`](app-builder#with_api) | Access to CosmWasm API. |
2222
| [Storage] | [`MockStorage`][MockStorage] | | [`with_storage`](app-builder#with_storage) | Access to storage. |
@@ -59,13 +59,13 @@ cosmwasm-std = "3"
5959
cw-multi-test = { version = "3", features = ["staking", "stargate", "cosmwasm_3_0"] }
6060
```
6161

62-
[Blocks]: ./introduction.md
63-
[Api]: ./introduction.md
64-
[Storage]: ./introduction.md
62+
[Blocks]: ./blocks.md
63+
[Api]: ./api.md
64+
[Storage]: ./storage.md
6565
[Bank]: ./introduction.md
6666
[Staking]: ./introduction.md
6767
[Distribution]: ./introduction.md
68-
[Governance]: ./introduction.md
68+
[Governance]: ./governance.md
6969
[Stargate]: ./introduction.md
7070
[Wasm]: ./introduction.md
7171
[Custom]: ./introduction.md

docs/multi-test/installation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ running tests faster with a clean and beautiful user interface.
4444

4545
Installing **Tarpaulin**:
4646

47-
```shell
47+
```shell title="terminal"
4848
cargo install cargo-tarpaulin
4949
```
5050

5151
Installing **cargo-nextest**:
5252

53-
```shell
53+
```shell title="terminal"
5454
cargo install cargo-nextest
5555
```
5656

0 commit comments

Comments
 (0)