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();
        }
    }
}

核心特性说明

  1. #[contract]宏:用于标记整个合约模块,是合约开发的入口点
  2. #[ink(storage)]:定义合约的存储结构,所有需要持久化的数据都应在此结构中声明
  3. #[ink(constructor)]:标记合约的构造函数,在合约部署时执行
  4. #[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(())
    }
}

注意事项

  1. 确保使用nightly版本的Rust编译器
  2. 合约代码必须满足no_std要求
  3. 所有公开的合约方法必须使用#[message]宏标记
  4. 合约存储结构必须使用#[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智能合约,减少样板代码,提高开发效率。

回到顶部