Rust智能合约开发库pallet-contracts-proc-macro的使用,支持Substrate区块链Wasm合约的宏扩展与代码生成
Rust智能合约开发库pallet-contracts-proc-macro的使用
安装方法
在您的项目目录中运行以下Cargo命令:
cargo add pallet-contracts-proc-macro
或者将以下行添加到您的Cargo.toml文件中:
pallet-contracts-proc-macro = "23.0.3"
基础使用示例
以下是一个展示如何使用pallet-contracts-proc-macro宏的完整智能合约示例:
// 导入必要的库和宏
use pallet_contracts_proc_macro::contract;
use ink_lang as ink;
// 使用contract宏定义智能合约
#[contract]
mod my_contract {
// 导入ink_lang中的必要类型
use ink_lang::{
contract,
env,
storage,
};
// 定义合约存储
#[ink(storage)]
pub struct MyContract {
value: storage::Value<u32>,
}
impl MyContract {
// 构造函数
#[ink(constructor)]
pub fn new(init_value: u32) -> Self {
Self {
value: storage::Value::new(init_value),
}
}
// 消息函数
#[ink(message)]
pub fn get_value(&self) -> u32 {
*self.value
}
// 另一个消息函数
#[ink(message)]
pub fn set_value(&mut self, new_value: u32) {
*self.value = new_value;
}
}
// 单元测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_works() {
let contract = MyContract::new(42);
assert_eq!(contract.get_value(), 42);
}
#[test]
fn set_value_works() {
let mut contract = MyContract::new(42);
contract.set_value(100);
assert_eq!(contract.get_value(), 100);
}
}
}
完整示例代码
下面是一个更完整的智能合约示例,展示了更多功能特性:
// 导入必要的库和宏
use pallet_contracts_proc_macro::contract;
use ink_lang as ink;
// 使用contract宏定义智能合约
#[contract]
mod advanced_contract {
use ink_lang::{
contract,
env,
storage,
};
use ink_prelude::string::String;
// 定义更复杂的合约存储
#[ink(storage)]
pub struct AdvancedContract {
owner: storage::Value<env::AccountId>,
name: storage::Value<String>,
balance: storage::Value<u128>,
is_active: storage::Value<bool>,
}
impl AdvancedContract {
// 构造函数 - 初始化合约
#[ink(constructor)]
pub fn new(name: String, initial_balance: u128) -> Self {
Self {
owner: storage::Value::new(env::caller()),
name: storage::Value::new(name),
balance: storage::Value::new(initial_balance),
is_active: storage::Value::new(true),
}
}
// 获取合约所有者
#[ink(message)]
pub fn get_owner(&self) -> env::AccountId {
*self.owner
}
// 获取合约名称
#[ink(message)]
pub fn get_name(&self) -> String {
self.name.clone()
}
// 获取合约余额
#[ink(message)]
pub fn get_balance(&self) -> u128 {
*self.balance
}
// 增加余额
#[ink(message, payable)]
pub fn deposit(&mut self, amount: u128) {
assert!(self.is_active(), "Contract is not active");
*self.balance += amount;
}
// 检查合约状态
#[ink(message)]
pub fn is_active(&self) -> bool {
*self.is_active
}
// 停用合约(仅所有者可调用)
#[ink(message)]
pub fn deactivate(&mut self) {
assert_eq!(
env::caller(),
*self.owner,
"Only owner can deactivate the contract"
);
*self.is_active = false;
}
}
// 单元测试
#[cfg(test)]
mod tests {
use super::*;
use ink_env::test;
#[test]
fn new_works() {
let contract = AdvancedContract::new("Test".to_string(), 1000);
assert_eq!(contract.get_name(), "Test");
assert_eq!(contract.get_balance(), 1000);
assert!(contract.is_active());
}
#[test]
fn deposit_works() {
let mut contract = AdvancedContract::new("Test".to_string(), 1000);
contract.deposit(500);
assert_eq!(contract.get_balance(), 1500);
}
#[test]
#[should_panic(expected = "Only owner can deactivate the contract")]
fn deactivate_permission() {
let accounts = test::default_accounts::<ink_env::DefaultEnvironment>();
test::set_caller::<ink_env::DefaultEnvironment>(accounts.alice);
let mut contract = AdvancedContract::new("Test".to_string(), 1000);
// 尝试用非所有者账户停用合约
test::set_caller::<ink_env::DefaultEnvironment>(accounts.bob);
contract.deactivate();
}
}
}
核心特性说明
#[contract]
宏:用于标记整个合约模块,是合约开发的入口点#[ink(storage)]
:定义合约的存储结构,所有需要持久化的数据都应在此结构中声明#[ink(constructor)]
:标记合约的构造函数,在合约部署时执行#[ink(message)]
:标记合约的可调用函数,分为查询类(只读)和修改类(可写)
技术规格
- 当前版本:23.0.3
- 使用许可:Apache-2.0
- 支持Rust 2021 edition
1 回复
Rust智能合约开发库pallet-contracts-proc-macro的使用指南
pallet-contracts-proc-macro
是一个用于Substrate区块链Wasm智能合约开发的Rust过程宏库,它简化了合约开发流程,提供了便捷的宏扩展和代码生成功能。
主要功能
- 自动生成合约ABI(应用程序二进制接口)
- 简化合约函数导出
- 提供合约开发常用宏
- 支持Wasm编译目标
安装方法
在项目的Cargo.toml
中添加依赖:
[dependencies]
pallet-contracts-proc-macro = { version = "0.9.0", default-features = false }
ink_primitives = { version = "3.0.0", default-features = false }
基本使用方法
1. 定义合约
使用#[contract]
宏标记合约结构体:
use pallet_contracts_proc_macro::contract;
#[contract]
pub struct MyContract {
value: i32,
}
2. 定义合约方法
使用#[message]
宏标记合约方法:
#[contract]
impl MyContract {
#[message]
pub fn new(initial_value: i32) -> Self {
Self { value: initial_value }
}
#[message]
pub fn get(&self) -> i32 {
self.value
}
#[message]
pub fn set(&mut self, new_value: i32) {
self.value = new_value;
}
}
3. 编译合约
确保在Cargo.toml
中正确配置了Wasm目标:
[lib]
crate-type = ["cdylib"]
[profile.release]
panic = "abort"
lto = true
然后使用以下命令编译:
cargo +nightly contract build
高级功能
事件定义
#[contract]
impl MyContract {
#[event]
pub struct ValueChanged {
#[indexed]
old_value: i32,
new_value: i32,
}
#[message]
pub fn set_with_event(&mut self, new_value: i32) {
let old_value = self.value;
self.value = new_value;
Self::emit_event(ValueChanged { old_value, new_value });
}
}
存储访问
#[contract]
impl MyContract {
#[storage]
pub struct Storage {
pub counter: i32,
pub owner: AccountId,
}
#[message]
pub fn increment(&mut self) {
self.storage.counter += 1;
}
}
错误处理
#[contract]
impl MyContract {
#[error]
pub enum Error {
Unauthorized,
InvalidValue,
}
#[message]
pub fn restricted_set(&mut self, new_value: i极速赛车开奖直播官网32) -> Result<(), Error> {
if new_value < 0 {
return Err(Error::InvalidValue);
}
self.value = new_value;
Ok(())
}
}
注意事项
- 确保使用nightly版本的Rust编译器
- 合约代码必须满足
no_std
要求 - 所有公开的合约方法必须使用
#[message]
宏标记 - 合约存储结构必须使用
#[storage]
宏标记
完整示例
#![no_std]
use pallet_contracts_proc_macro::contract;
use ink_primitives::AccountId;
#[contract]
pub struct MyToken {
#[storage]
pub storage: Storage,
}
#[contract]
impl MyToken {
#[storage]
pub struct Storage {
balances: ink_storage::collections::HashMap<AccountId, u64>,
total_supply: u64,
}
#[event]
pub struct Transfer {
#[indexed]
from: Option<AccountId>,
#[indexed]
to: Option<AccountId>,
value: u64,
}
#[error]
pub enum Error {
InsufficientBalance,
Overflow,
}
#[message]
pub fn new(initial_supply: u64) -> Self {
let caller = Self::env().caller();
let mut balances = ink_storage::collections::HashMap::new();
balances.insert(caller, initial_supply);
Self {
storage: Storage {
balances,
total_supply: initial_supply,
},
}
}
#[message]
pub fn transfer(&mut self, to: AccountId, value: u64) -> Result<(), Error> {
let from = self.env().caller();
let from_balance = self.storage.balances.get(&from).copied().unwrap_or(0);
if from_balance < value {
return Err(Error::InsufficientBalance);
}
let to_balance = self.storage.balances.get(&to).copied().unwrap_or(0);
let new_to_balance = to_balance.checked_add(value)
.ok_or(Error::Overflow)?;
self.storage.balances.insert(from, from_balance - value);
self.storage.balances.insert(to, new_to_balance);
Self::emit_event(Transfer {
from: Some(from),
to: Some(to),
value,
});
Ok(())
}
#[message]
pub fn balance_of(&self, owner: AccountId) -> u64 {
self.storage.balances.get(&owner).copied().unwrap_or(0)
}
}
通过使用pallet-contracts-proc-macro
库,开发者可以更高效地编写Substrate区块链的Wasm智能合约,减少样板代码,提高开发效率。