Allureluoli 二月FEBRUARY

区块链国赛笔记 10|Rust 智能合约初识:ink! 存储、消息与单元测试

这是备赛时对 Rust 合约方向的一次补充学习,重点是理解属性宏、存储、构造函数和测试入口。

本文由个人备赛旧笔记整理,整理日期为 2026-11-03。命令、输出和测试记录属于当时的实验环境;本文未重新搭建整套环境验证。

阅读前先确认

原笔记使用 ink_lang 风格的旧版 API,未记录完整 Cargo 依赖与工具链。代码按学习片段保留,不视为可直接构建的完整项目。

简单合约

简单合约及其测试

合约代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#![cfg_attr(not(feature = "std"), no_std)]
// 编译属性声明
// #! 表示创建级别属性 no_std 模式
// no_std 表示不使用 标准库 合约 不使用标准库很重要


// 整体合约基于 !ink 框架
use ink_lang as ink;
// 使用 ink_lang

#[ink::contract] // 宏标记 ink 合约
mod hello_world { // 定义合约模块
#[ink(storage)] // 标记合约存储结构
pub struct HelloWorld {
value: i32, // 合约结构体
}

impl HelloWorld { // 定义实现块
#[ink(constructor)] // 标记构造函数
pub fn new(init_value: i32) -> Self {
Self { value: init_value } // 接收初始值 创建合约实例
}

#[ink(constructor)]
pub fn default() -> Self { // 创建默认值为0的合约实例
Self::new(0)
}

#[ink(message)]
pub fn get(&self) -> i32 { // 构造get 返回值
self.value
}

#[ink(message)]
pub fn set(&mut self, new_value: i32) { // 构造set 设置值
self.value = new_value;
}
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#![cfg(test)] // 测试属性声明

use ink_lang as ink;

use ink_env::{
test::{
default_accounts, // 获取测试账户
set_caller, // 模拟不同账户
set_value_transferred, // 设置转账金额
get_account_balance // 查询账户余额
},
DefaultEnvironment,
};
use ink_primitives::AccountId;

// 导入合约模块
use hello_world::HelloWorld;

#[ink::test]
fn new_works() {
// 测试构造函数
let contract = HelloWorld::new(42);
assert_eq!(contract.get(), 42); // 构造12 测试能不能get 12
}

#[ink::test]
fn default_works() {
// 测试默认构造函数
let contract = HelloWorld::default(); // 测试无参构造函数
assert_eq!(contract.get(), 0); // 验证0
}

#[ink::test]
fn set_and_get_work() {
// 测试 set 和 get 方法
let mut contract = HelloWorld::new(10);

// 初始值检查
assert_eq!(contract.get(), 10);

// 设置新值
contract.set(100);

// 验证新值
assert_eq!(contract.get(), 100);
}

#[ink::test]
fn multiple_set_operations() {
// 测试多次设置操作
let mut contract = HelloWorld::default();

contract.set(5);
assert_eq!(contract.get(), 5);

contract.set(-10);
assert_eq!(contract.get(), -10);

contract.set(0);
assert_eq!(contract.get(), 0);
}

#[ink::test]
fn test_with_different_accounts() {
// 测试不同账户调用
let accounts = default_accounts::<DefaultEnvironment>();

// 使用 Alice 账户部署合约
set_caller::<DefaultEnvironment>(accounts.alice);
let mut contract = HelloWorld::new(50);
assert_eq!(contract.get(), 50);

// 使用 Bob 账户调用(在真实环境中会有权限检查)
set_caller::<DefaultEnvironment>(accounts.bob);
contract.set(75);
assert_eq!(contract.get(), 75);
}

#[ink::test]
fn test_edge_cases() {
// 测试边界情况
let mut contract = HelloWorld::new(i32::MAX);
assert_eq!(contract.get(), i32::MAX);

contract.set(i32::MIN);
assert_eq!(contract.get(), i32::MIN);

contract.set(0);
assert_eq!(contract.get(), 0);
}

#[ink::test]
fn test_constructor_variants() {
// 测试不同的构造函数
let contract1 = HelloWorld::new(123);
let contract2 = HelloWorld::default();

assert_eq!(contract1.get(), 123);
assert_eq!(contract2.get(), 0);
}

// 集成测试示例
#[cfg(test)]
mod integration_tests {
use super::*;

#[ink::test]
fn complete_workflow() {
// 完整的工作流程测试
let mut contract = HelloWorld::default();

// 初始状态
assert_eq!(contract.get(), 0);

// 执行操作
contract.set(42);

// 验证结果
assert_eq!(contract.get(), 42);

// 再次更新
contract.set(100);
assert_eq!(contract.get(), 100);
}
}

编译和测试过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌──(cure㉿LAPTOP-CMAM5D0J)-[~/hello_world]
└─$ cargo contract build
[==] Checking clippy linting rules
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.15s
[==] Building cargo project
Finished `release` profile [optimized] target(s) in 0.20s

The contract was built in DEBUG mode.

Your contract artifacts are ready. You can find them in:
/home/cure/hello_world/target/ink

- hello_world.contract (code + metadata)
- hello_world.wasm (the contract's code)
- hello_world.json (the contract's metadata)

┌──(cure㉿LAPTOP-CMAM5D0J)-[~/hello_world]
└─$ cargo test
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.44s
warning: the following packages contain code that will be rejected by a future version of Rust: subxt v0.35.3, trie-db v0.28.0
note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1`
Running unittests lib.rs (target/debug/deps/hello_world-d8195df315de2005)

running 2 tests
test hello_world::tests::default_works ... ok
test hello_world::tests::it_works ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Doc-tests hello_world

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

复现时的自查

  • 记录自己实际使用的版本、配置和缺失依赖。
  • 对照本篇关键步骤,保存命令或调用结果,并解释结果代表什么。
  • 对失败或与原记录不一致的情况保留错误信息,不把历史输出当成自己的验证结果。

返回系列导读 · 上一篇 · 下一篇

评论COMMENTS