Substrate区块链应用开发-存证模块的功能开发

Substrate区块链应用开发-存证模块的功能开发

    • 链上存证介绍
    • 最小化substrate代码开发
      • 来源substrate官方维护的最小框架
        • 关注pallets和runtime
          • 1. pallets template
            • 2.runtime
        • pallets poe 模块编写
          • 建立poe模块
            • 1.复制pallets/template 为 pallets/poe
            • 2.修改poe的Cargo.toml配置文件
            • 3.修改poe的lib.rs文件
            • 4. decl_storage 定义存储单元
            • 5. decl_module 创建存证
            • 6.decl_error 异常处理
            • 7. decl_event 事件处理
            • 8. 撤销存证
            • 9. 将第8步中用到的异常处理和事件进行声明
        • 在runtime中引入poe模块
        • 在runtime/src/lib.rs中引入配置接口
          • 实现配置接口
          • 引入poe接口对应的操作信息

链上存证介绍

Substrate区块链应用开发-存证模块的功能开发_第1张图片

最小化substrate代码开发

来源substrate官方维护的最小框架

substrate-node-template 是substrate的最小化框架,最小实现,麻雀虽小,五脏俱全,适合新手入门和理解substrate
https://github.com/substrate-developer-hub/substrate-node-template

关注pallets和runtime

1. pallets template

存证模板

2.runtime

应用实现
Substrate区块链应用开发-存证模块的功能开发_第2张图片

pallets poe 模块编写

poe : proof of existence

建立poe模块
1.复制pallets/template 为 pallets/poe

Substrate区块链应用开发-存证模块的功能开发_第3张图片

2.修改poe的Cargo.toml配置文件

修改[package]的description和name
描述和名字可自定义
Substrate区块链应用开发-存证模块的功能开发_第4张图片

3.修改poe的lib.rs文件

认识lib.rs构成
lib.rs:模板引入依赖、主程序、存储单元(宏)、事件(宏)、异常处理(宏)、可调用函数(宏)
Substrate区块链应用开发-存证模块的功能开发_第5张图片

4. decl_storage 定义存储单元

目标:先定义一个存储单元,用于存储存在归属信息
代码实现:
(1) 定义一个存储项 Proofs,给它一个default get散户,称之为 proofs
(2) 给Proofs设置类型为map,map的key是Vec,即存证hash值,由于无法得知使用哪些hash函数,所以使用变长类型u8
(3)存证归属信息需要归属到一个人身上,以及它在哪个时间点被存储。这里定义一个tuple,给定两个参数,一个是用户信息(AccountId),一个是区块链时间(BlockNumber)
(4)由于Vec是由用户输入,属于非安全的,这里得使用blake2_128_concat
(5)一个简单存储单元编码完成,可以使用cargo check或者cargo build来检查语法是否有错误
(6)使用了Vec,需要引入依赖

use sp_std::prelude::*;  // 使用了Vec

Substrate区块链应用开发-存证模块的功能开发_第6张图片

5. decl_module 创建存证

注意:Proofs存储项是在decl_storage存储单元中定义的
(1)我们需要创建一个存证,创建存证需要有两个关键参数:交易发送方origin,和存证hash值claim,由于存证使用的hash函数是未知的,也需要和上面decl_storage定义对应,这里需要使用变长Vec来保存存证
(2)创建存证之前,我们需要“Verify First,Write Last”的原则,先对存证内容进行检查,检查两个方面:
:交易发送方是不是一个签名的用户;
:存证是否被别人创建过,创建过就得抛出异常(由decl_error处理)
(3)通过ensuer_signed来验证存证拥有人sender就是交易发送方origin
(4)通过Proofs::::contains_key传参claim的引用去获取存证,不存在就抛出异常Error::::ProofAlreadyExist,该异常ProofAlreadyExit需要由decl_error处理
(5)如果通过检查校验,开始插入操作:insert是一个map的key-value插入操作,这里的key-value是一个tuple,这个tuple的第一个元素是AccountId;第二个元素是当前交易所处的区块,使用系统模块提供的block_number工具方法获取;
(6)插入完毕,触发一个event时间来通知客户端,RawEvent由宏生成(为啥使用该宏?)

        // 创建存证,创建存证需要有两个关键参数:交易发送方origin,存证hash值claim,由于存证hash函数未知,也和decl_storage定义对应,这里使用变长Vec
        #[weight = 0]
		pub fn create_claim(origin,claim:Vec)->dispatch::DispatchResult{
			// 做必要检查,检查内容: 1,交易发送方是不是一个签名的用户 2,存证是否被别人创建过,创建过就抛出错误
			// 首先去创建签名交易,通过ensure_signed这样的system提供的版本方法来校验
			let sender = ensure_signed(origin)?;  // 存证拥有人是交易发送方,只有拥有人才可以调用存证,sender即当前交易发送方
  			// 如果存在存证,返回错误 ProofAlreadyExist
  			// ps:ensure!宏是确保表达式中的结果为true,这里取反操作
			ensure!(!Proofs::::contains_key(&claim),Error::::ProofAlreadyExist);  // 这里用到一个错误  ProofAlreadyExist,该错误需要在decl_error声明
			// 做insert操作,insert是key-value方式。这里的key-value是一个tuple
			// 这个tuple的第一个元素是AccountId;第二个是当前交易所处的区块,使用系统模块提供的block_number工具方法获取
			Proofs::::insert(&claim,(sender.clone(),system::Module::::block_number()));  // 插入操作
			// 触发一个event来通知客户端,RawEvent由宏生成;   sender:存在拥有人;claim:存在hash值 通过event通知客户端
			Self::deposit_event(RawEvent::ClaimCreated(sender,claim));   // ClaimCreated事件,需要decl_event处理
			// 返回ok
			Ok(())

		}
6.decl_error 异常处理

将decl_module中定义的存证异常ProofAlreadyExist,需要在decl_error中声明

// 异常处理
// The pallet's errors
decl_error! {
	pub enum Error for Module {
		ProofAlreadyExist,    // 存在异常,即存证已经存在
	}
}
7. decl_event 事件处理

将decl_module中定义的ClaimCreated事件在decl_evnet中声明处理

// 事件
// The pallet's events
decl_event!(
	pub enum Event where AccountId = ::AccountId {
		ClaimCreated(AccountId,Vec),  // 用户AccountId,存证内容 Vec
	}
);
8. 撤销存证
#[weight = 0]
		pub fn revoke_claim(origin,claim: Vec) -> dispatch::DispatchResult{
			let sender = ensure_signed(origin)?;  // 交易发送方式已签名的, 存证拥有人是交易发送方,只有拥有人才可以吊销存证

  			// 判断存储单元里面是存在这样一个存证;如果不存在,抛出错误,错误我们叫ClaimNotExist
			ensure!(Proofs::::contains_key(&claim),Error::::ClaimNotExist);

			// 获取这样的存证  owner: accountId   block_number
			let (owner,_block_number) = Proofs::::get(&claim);  // 通过get api获取这样的一个存证

			ensure!(owner == sender,Error::::NotClaimOwner);  // 确保交易发送方是我们的存证人,如果不是,返回Error,这个Error我们叫NotClaimOwner

			// 以上校验完成之后,我们就可以删除我们的存证
		    // 存储向上调用remove函数进行删除
		    Proofs::::remove(&claim);

			// 触发一个事件,返回存证人和hash
		    Self::deposit_event(RawEvent::ClaimRevoked(sender,claim));

			// 返回
			Ok(())


		}
9. 将第8步中用到的异常处理和事件进行声明
// 事件
// The pallet's events
decl_event!(
	pub enum Event where AccountId = ::AccountId {
		ClaimCreated(AccountId,Vec),  // 用户AccountId,存证内容 Vec
		ClaimRevoked(AccountId,Vec),
	}
);

// 异常处理
// The pallet's errors
decl_error! {
	pub enum Error for Module {
		ProofAlreadyExist,    // 存证已经存在
		ClaimNotExist,
		NotClaimOwner,
	}
}

在runtime中引入poe模块

在runtime/Cargo.toml 中添加poe模块

# 引入poe依赖
[dependencies.poe]
default-features = false
package = 'pallet-poe'
path = '../pallets/poe'
version = '2.0.0-rc2'
[features]
default = ['std']
std = [
    'aura/std',
    'balances/std',
    'codec/std',
    'frame-executive/std',
    'frame-support/std',
    'grandpa/std',
    'randomness-collective-flip/std',
    'serde',
    'sp-api/std',
    'sp-block-builder/std',
    'sp-consensus-aura/std',
    'sp-core/std',
    'sp-inherents/std',
    'sp-io/std',
    'sp-offchain/std',
    'sp-runtime/std',
    'sp-session/std',
    'sp-std/std',
    'sp-transaction-pool/std',
    'sp-version/std',
    'sudo/std',
    'system/std',
    'timestamp/std',
    'transaction-payment/std',
    'template/std',
    'poe/std',  # 增加标签
]

在runtime/src/lib.rs中引入配置接口

实现配置接口
/// 对配置接口进行实现
impl poe::Trait for Runtime{
	type Event = Event;
}
引入poe接口对应的操作信息
construct_runtime!(
	pub enum Runtime where
		Block = Block,
		NodeBlock = opaque::Block,
		UncheckedExtrinsic = UncheckedExtrinsic
	{
		System: system::{Module, Call, Config, Storage, Event},
		RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
		Timestamp: timestamp::{Module, Call, Storage, Inherent},
		Aura: aura::{Module, Config, Inherent(Timestamp)},
		Grandpa: grandpa::{Module, Call, Storage, Config, Event},
		Balances: balances::{Module, Call, Storage, Config, Event},
		TransactionPayment: transaction_payment::{Module, Storage},
		Sudo: sudo::{Module, Call, Config, Storage, Event},
		// Used for the module template in `./template.rs`
		TemplateModule: template::{Module, Call, Storage, Event},
		// 引入poe对应模块的操作信息  Module: 模块  Call:调用函数  Storage:存储项  Event:事件  Error不需要额外引入
		PoeModule: poe::{Module, Call, Storage, Event},
	}
);

你可能感兴趣的:(rust,substrate)