Rust区块链智能合约开发库CosmWasm-core的使用,CosmWasm-core为Rust生态提供模块化WASM虚拟机与Cosmos SDK集成方案
cosmwasm-core
这个crate包含了可以在no_std环境中使用的cosmwasm-std组件。所有的符号都被cosmwasm-std重新导出,因此合约开发者不需要直接添加这个依赖。建议尽可能只使用cosmwasm-std。
许可证
这个包是cosmwasm仓库的一部分,遵循Apache License 2.0许可证。
安装
在你的项目目录中运行以下Cargo命令:
cargo add cosmwasm-core
或者在你的Cargo.toml中添加以下行:
cosmwasm-core = "3.0.1"
完整示例代码
以下是一个使用cosmwasm-core开发智能合约的完整示例:
// 导入必要的模块
use cosmwasm_std::{Response, StdResult, DepsMut, Env, MessageInfo};
use cosmwasm_core::exports::Extern;
// 定义合约消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum ExecuteMsg {
// 在这里定义你的合约消息
Example { value: String },
}
// 执行函数
pub fn execute(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: ExecuteMsg,
) -> StdResult<Response> {
match msg {
ExecuteMsg::Example { value } => {
// 处理示例消息
Ok(Response::new().add_attribute("action", "example"))
}
}
}
// 初始化函数
pub fn instantiate(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: InstantiateMsg,
) -> StdResult<Response> {
Ok(Response::default())
}
// 查询函数
pub fn query(_deps: Deps, _env: Env, _msg: QueryMsg) -> StdResult<Binary> {
// 实现你的查询逻辑
unimplemented!()
}
// 定义合约入口点
#[cfg(target_arch = "wasm32")]
mod wasm {
use super::*;
use cosmwasm_std::{do_handle, do_init, do_query};
#[no_mangle]
extern "C" fn init(env_ptr: u32, msg_ptr: u32) -> u32 {
do_init(
&instantiate,
env_ptr,
msg_ptr,
)
}
#[no_mangle]
extern "C" fn handle(env_ptr: u32, info_ptr: u32, msg_ptr: u32) -> u32 {
do_handle(
&execute,
env_ptr,
info_ptr,
msg_ptr,
)
}
#[no_mangle]
extern "C" fn query(env_ptr: u32, msg_ptr: u32) -> u32 {
do_query(
&query,
env_ptr,
msg_ptr,
)
}
}
这个示例展示了如何使用cosmwasm-core开发一个基本的智能合约,包括:
- 定义合约消息
- 实现执行函数
- 实现初始化函数
- 实现查询函数
- 定义WASM入口点
注意:在实际开发中,你应该使用cosmwasm-std而不是直接使用cosmwasm-core,除非你有特殊的需求需要在no_std环境中运行。
完整示例demo
以下是一个更完整的cosmwasm-core智能合约示例:
// 导入所有必要的模块
use cosmwasm_std::{
Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use cosmwasm_core::exports::Extern;
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
// 定义初始化消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub admin: String,
}
// 定义执行消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum ExecuteMsg {
UpdateAdmin { new_admin: String },
ExecuteAction { data: String },
}
// 定义查询消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum QueryMsg {
GetAdmin {},
GetContractInfo {},
}
// 定义合约状态
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub admin: String,
pub version: String,
}
// 初始化函数
pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
let state = State {
admin: msg.admin,
version: "1.0".to_string(),
};
// 存储状态
deps.storage.set(b"state", &to_vec(&state)?);
Ok(Response::new().add_attribute("action", "instantiate"))
}
// 执行函数
pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> StdResult<Response> {
match msg {
ExecuteMsg::UpdateAdmin { new_admin } => {
// 验证调用者是否是当前管理员
let mut state: State = from_slice(&deps.storage.get(b"state").unwrap())?;
if info.sender != state.admin {
return Err(StdError::unauthorized());
}
// 更新管理员
state.admin = new_admin;
deps.storage.set(b"state", &to_vec(&state)?);
Ok(Response::new().add_attribute("action", "update_admin"))
}
ExecuteMsg::ExecuteAction { data } => {
// 执行某些操作
Ok(Response::new()
.add_attribute("action", "execute")
.add_attribute("data", data))
}
}
}
// 查询函数
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::GetAdmin {} => {
let state: State = from_slice(&deps.storage.get(b"state").unwrap())?;
to_binary(&state.admin)
}
QueryMsg::GetContractInfo {} => {
let state: State = from_slice(&deps.storage.get(b"state").unwrap())?;
to_binary(&state)
}
}
}
// WASM入口点
#[cfg(target_arch = "wasm32")]
mod wasm {
use super::*;
use cosmwasm_std::{do_handle, do_init, do_query};
#[no_mangle]
extern "C" fn init(env_ptr: u32, msg_ptr: u32) -> u32 {
do_init(&instantiate, env_ptr, msg_ptr)
}
#[no_mangle]
extern "C" fn handle(env_ptr: u32, info_ptr: u32, msg_ptr: u32) -> u32 {
do_handle(&execute, env_ptr, info_ptr, msg_ptr)
}
#[no_mangle]
extern "C" fn query(env_ptr: u32, msg_ptr: u32) -> u32 {
do_query(&query, env_ptr, msg_ptr)
}
}
这个完整示例展示了:
- 完整的合约状态管理
- 管理员权限控制
- 多种消息类型处理
- 状态存储和查询
- 错误处理
- WASM入口点实现
注意:实际开发中仍建议优先使用cosmwasm-std,除非确实需要在no_std环境中运行。
Rust区块链智能合约开发库CosmWasm-core使用指南
简介
CosmWasm-core是一个专为Cosmos生态系统设计的智能合约开发库,它允许开发者使用Rust编写WebAssembly(WASM)智能合约,并与Cosmos SDK无缝集成。该库提供了模块化的WASM虚拟机实现,是构建去中心化应用(dApps)和区块链间通信(IBC)的理想选择。
主要特性
- 基于Rust的安全智能合约开发环境
- 高性能WASM虚拟机执行引擎
- 与Cosmos SDK原生集成
- 模块化设计,易于扩展
- 支持跨链通信(IBC)
- 提供丰富的标准库和工具链
安装与配置
首先,在Cargo.toml中添加依赖:
[dependencies]
cosmwasm-std = "1.0"
cosmwasm-storage = "1.0"
schemars = "0.8"
serde = { version = "1.0", features = ["derive"] }
基本使用示例
1. 创建简单智能合约
use cosmwasm_std::{
entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub count: i32,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum ExecuteMsg {
Increment {},
Reset { count: i32 },
}
#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
Ok(Response::default())
}
#[entry_point]
pub fn execute(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: ExecuteMsg,
) -> StdResult<Response> {
match msg {
ExecuteMsg::Increment {} => Ok(Response::default()),
ExecuteMsg::Reset { count } => Ok(Response::default()),
}
}
2. 编译为WASM
在项目根目录下运行:
RUSTFLAGS='-C link-arg=-s' cargo wasm
3. 优化WASM文件
docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/rust-optimizer:0.12.6
高级功能
1. 状态管理
use cosmwasm_std::{StdResult, Storage};
use cosmwasm_storage::{singleton, singleton_read};
pub static CONFIG_KEY: &[u8] = b"config";
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub count: i32,
pub owner: Addr,
}
pub fn store_config(storage: &mut dyn Storage, config: &State) -> StdResult<()> {
singleton(storage, CONFIG_KEY).save(config)
}
pub fn read_config(storage: &dyn Storage) -> StdResult<State> {
singleton_read(storage, CONFIG_KEY).load()
}
2. 跨合约调用
use cosmwasm_std::{to_binary, CosmosMsg, WasmMsg};
pub fn call_other_contract(
contract_addr: Addr,
msg: &ExecuteMsg,
) -> StdResult<CosmosMsg> {
Ok(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: contract_addr.to_string(),
msg: to_binary(msg)?,
funds: vec![],
}))
}
测试合约
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary};
#[test]
fn proper_initialization() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg { count: 17 };
let info = mock_info("creator", &coins(1000, "earth"));
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
}
}
部署到Cosmos链
- 上传合约代码:
wasmd tx wasm store contract.wasm --from wallet --chain-id my-chain --gas auto -y
- 实例化合约:
wasmd tx wasm instantiate $CODE_ID '{"count":0}' --from wallet --label "my contract" --chain-id my-chain --gas auto -y
- 执行合约方法:
wasmd tx wasm execute $CONTRACT_ADDR '{"increment":{}}' --from wallet --chain-id my-chain --gas auto -y
最佳实践
- 使用Rust的安全特性(如所有权模型)来防止常见漏洞
- 为所有公共消息和状态实现Schema
- 编写全面的单元测试和集成测试
- 使用
cosmwasm-check
工具验证合约 - 遵循最小权限原则设计合约访问控制
CosmWasm-core为Rust开发者提供了强大的工具来构建安全、高效的区块链智能合约,特别适合Cosmos生态系统中的跨链应用开发。
完整示例代码
use cosmwasm_std::{
entry_point, Binary, Deps, DepsMut, Env, MessageInfo,
Response, StdResult, Addr, Storage
};
use cosmwasm_storage::{singleton, singleton_read};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
// 合约状态结构体
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub count: i32,
pub owner: Addr,
}
// 初始化消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub count: i32,
}
// 执行消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum ExecuteMsg {
Increment {},
Reset { count: i32 },
GetCount {},
}
// 查询消息
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum QueryMsg {
GetCount {},
}
// 查询响应
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct CountResponse {
pub count: i32,
}
// 状态存储键
pub static CONFIG_KEY: &[u8] = b"config";
// 初始化函数
#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
let state = State {
count: msg.count,
owner: info.sender,
};
store_config(deps.storage, &state)?;
Ok(Response::default())
}
// 执行函数
#[entry_point]
pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> StdResult<Response> {
match msg {
ExecuteMsg::Increment {} => increment(deps, info),
ExecuteMsg::Reset { count } => reset(deps, info, count),
ExecuteMsg::GetCount {} => get_count(deps),
}
}
// 增加计数器
fn increment(deps: DepsMut, info: MessageInfo) -> StdResult<Response> {
let mut state = read_config(deps.storage)?;
if info.sender != state.owner {
return Err(StdError::unauthorized());
}
state.count += 1;
store_config(deps.storage, &state)?;
Ok(Response::default())
}
// 重置计数器
fn reset(deps: DepsMut, info: MessageInfo, count: i32) -> StdResult<Response> {
let mut state = read_config(deps.storage)?;
if info.sender != state.owner {
return Err(StdError::unauthorized());
}
state.count = count;
store_config(deps.storage, &state)?;
Ok(Response::default())
}
// 获取计数器值
fn get_count(deps: DepsMut) -> StdResult<Response> {
let state = read_config(deps.storage)?;
Ok(Response::new().add_attribute("count", state.count.to_string()))
}
// 查询函数
#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::GetCount {} => query_count(deps),
}
}
// 查询计数器值
fn query_count(deps: Deps) -> StdResult<Binary> {
let state = read_config(deps.storage)?;
let resp = CountResponse { count: state.count };
to_binary(&resp)
}
// 存储配置
pub fn store_config(storage: &mut dyn Storage, config: &State) -> StdResult<()> {
singleton(storage, CONFIG_KEY).save(config)
}
// 读取配置
pub fn read_config(storage: &dyn Storage) -> StdResult<State> {
singleton_read(storage, CONFIG_KEY).load()
}
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary, StdError};
#[test]
fn proper_initialization() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg { count: 17 };
let info = mock_info("creator", &coins(1000, "earth"));
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
let state = read_config(&deps.storage).unwrap();
assert_eq!(17, state.count);
assert_eq!("creator", state.owner);
}
#[test]
fn increment() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg { count: 17 };
let info = mock_info("creator", &coins(2, "token"));
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("creator", &coins(2, "token"));
let msg = ExecuteMsg::Increment {};
let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let state = read_config(&deps.storage).unwrap();
assert_eq!(18, state.count);
}
#[test]
fn reset() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg { count: 17 };
let info = mock_info("creator", &coins(2, "token"));
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("creator", &coins(2, "token"));
let msg = ExecuteMsg::Reset { count: 5 };
let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let state = read_config(&deps.storage).unwrap();
assert_eq!(5, state.count);
}
#[test]
fn unauthorized_reset() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg { count: 17 };
let info = mock_info("creator", &coins(2, "token"));
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("someone", &coins(2, "token"));
let msg = ExecuteMsg::Reset { count: 5 };
let res = execute(deps.as_mut(), mock_env(), info, msg);
match res {
Err(StdError::Unauthorized { .. }) => {}
_ => panic!("Must return unauthorized error"),
}
}
}