-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHomework5.rs
132 lines (119 loc) · 5.28 KB
/
Homework5.rs
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
126
127
128
129
130
131
132
/**
@author 韩峰 - 08 - Team1
@date 2021-08-13
*/
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::*;
// 首先通过 frame_support::pallet 宏创建 pallet
#[frame_support::pallet]
pub mod pallet {
// 引入需要的包
use frame_support::{
dispatch::DispatchResultWithPostInfo,
pallet_prelude::*,
};
// 比较粗暴的引用 frame_system 所有宏函数,和系统类型信息
use frame_system::pallet_prelude::*;
use sp_std::vec::Vec;
//创建配置接口,通过 config 宏完成
//继承自系统模块的 Config 接口,只有一个
#[pallet::config]
pub trait Config: frame_system::Config {
// 只有一个关联类型就是 Event,并且约束
// 可以从本模块的Event 类型进行转换,并且它的类型是一个系统模块的Event 类型。
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}
// 定义一个结构体类型,来承载整个功能模块,使用 pallet::pallet 这个宏进行定义
#[pallet::pallet]
// 表示这个模块依赖的存储单元,一级存储单元依赖的 trait
#[pallet::generate_store(pub (super) trait Store)]
pub struct Pallet<T>(_);
// 通过 storage 宏来定义存储类型,用来存储存证
#[pallet::storage]
// 这里定义的getter方法可以通过前段接口进行调用 my_proofs 方法来查询连上的状态,也就是说没必要单独写一个读取的接口。
#[pallet::getter(fn my_proofs)]
pub type Proofs<T: Config> = StorageMap<
_,
Blake2_128Concat,
Vec<u8>, // 存证的哈希值
(T::AccountId, T::BlockNumber) // 值时两个元素的tuple,第一个是AccountId, 第二个存储区块高度。
>;
// 通过 Event 定义一个时间存储类型,这是一个枚举。
#[pallet::event]
// 生成一个 转换后的 metadata 方便前段接收
#[pallet::metadata(T::AccountId = "AccountId")]
// 生成一个帮助性的方法,方便这个方法进行触发。
#[pallet::generate_deposit(pub (super) fn deposit_event)]
pub enum Event<T: Config> {
ClaimCreated(T::AccountId, Vec<u8>),
ClaimRevoked(T::AccountId, Vec<u8>),
TransferClaim(T::AccountId, Vec<u8>, T::AccountId),
}
// 通过 error 宏定义一个错误信息
#[pallet::error]
pub enum Error<T> {
// 定义一个错误信息,存证已经存在
ProofAlreadyExist,
ClaimNotExist,
NotClaimOwner,
}
// 定义一个 hooks ,如果有初始化区块的信息可以放到这里面,如果没有这个也必须要加上否则会报错
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
// 构建可调用函数,通过 call 这个宏
#[pallet::call]
impl<T: Config> Pallet<T> {
// 为了测试方便起见,weight 给入 0 值,实际应用中需要根据实际情况进行预估。
#[pallet::weight(0)]
pub fn create_claim(
// 这个参数表示交易的发送方
origin: OriginFor<T>,
// 表示存证的哈希值,对应 38行。
claim: Vec<u8>,
) -> DispatchResultWithPostInfo { // 返回值是一个Result类型的别名它会包含一些weight的信息,这是通过use引入进来的
// TODO:: 写入创建存证的逻辑。
// 验证签名信息是否合法
let sender = ensure_signed(origin)?;
// 判断存证信息是否存在
ensure!(!Proofs::<T>::contains_key(&claim), Error::<T>::ProofAlreadyExist);
// 插入存证
Proofs::<T>::insert(
&claim,
(sender.clone(), frame_system::Pallet::<T>::block_number()),
);
// 发送事件
Self::deposit_event(Event::ClaimCreated(sender, claim));
// 返回结果信息,并进行类型转换。
Ok(().into())
}
// 建立一个吊销存证的方法
#[pallet::weight(0)]
pub fn revoke_claim(
origin: OriginFor<T>,
claim: Vec<u8>,
) -> DispatchResultWithPostInfo {
// 先验证 origin
let sender = ensure_signed(origin)?;
let (owner, _) = Proofs::<T>::get(&claim).ok_or(Error::<T>::ClaimNotExist)?;
// 判断发送者和存证所有者是否是同一个人
ensure!(owner == sender, Error::<T>::NotClaimOwner);
// 删除存证
Proofs::<T>::remove(&claim);
// 发送存证Revoked事件
Self::deposit_event(Event::ClaimRevoked(sender, claim));
// 返回函数成功结果
Ok(().into())
}
//建立一个转移存证的方法
#[pallet::weight(0)]
pub fn transfer_claim(origin: OriginFor<T>, claim: Vec<u8>, dest: T::AccountId) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
ensure!(Proofs::<T>::contains_key(&claim), Error::<T>::ClaimNotExist);
let (owner, _block_number) = Proofs::<T>::get(&claim);
ensure!(owner == sender, Error::<T>::NotClaimOwner);
Proofs::<T>::insert(&claim, (dest.clone(), frame_system::Pallet::<T>::block_number()));
Self::deposit_event(Event::TransferClaim(sender, claim, dest));
Ok(().into())
}
}
}