Sub Dev 讨论 | 看完 Rust 功力瞬间提高一层
一块链习是首家区块链技术学习社区,提供最系统的区块链技术课程学习,定期出品有深度的技术观察 + 评论。
《从0到一学会Substrate 区块链应用开发》由一块链习和Parity官方联合出品,专为区块链技术爱好者量身打造,并由 王大锤,陈锡亮,孙凯超,朱振明四位老师联合授课。
目前第一期课程已经进行到第三周,同学们会在班级群讨论学习中遇到的难题或不解。另外每周日上午 10 点,都会进行课程内容知识拓展——作业点评会和在线答疑。
现在将第二周班级群日常优质的讨论内容和徐杨助教对第三课的作业点评分享给大家。
陈威-学员:请问一下,多签的搜集过程是怎么样的?
王晓玮-助教:1. 判断 brige-eos 模块中是否有需要签名的跨链交易;2. 判断当前出块节点是否有签名的权限;3. 从 local storage 中取出签名私钥。4. 对交易进行签名;5. 将签名结果存储到链上;6. 如果签名数量超过阈值,就通过HTTP请求发送跨链交易。
陈威-学员:签名结果存到链上,这里是需要手续费的吧。
王晓玮-助教:是的,手续费这块还在设计。
陈威-学员:以前用过以太坊的多签。好像是p2p直接广播。不入块的。
王晓玮-助教:嗯,这样也可以,不过无法在 pallet 里面实现,需要改 substrate 底层了。
陈威-学员:只有最终搜集好了,才是真的交易。
02
红军大叔-学员:
这种用法还没习惯 。
樊金辉-学员:
简单粗暴的理解,套上专业术语,偏差不大。
再直接一些,T是参数,终究是要消掉的或者换为具体类型,
1. 如果在::左侧,可直接换为T
2. 如若在标识符右侧,则整体可以删除
最后T换为具体类型。
徐杨-助教:主要是三个逻辑:
Type as Trait
Trait::Type
Trait<Type>
把这三个逻辑套用与叠加,就会出现各种具体用法了。
廖师虎-学员:这三种都是什么逻辑?
徐杨-助教:
type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
Type as Trait,就是把一个类型转成它impl的一个trait
在我们的例子里,<T as Trait>就是这个用法,T是范型参数,
转成T impl的一个接口Trait,Trait是lib.rs里面已经定义了的
pub trait Trait: system::Trait {
。。。
}
经过这个步骤,我们通过范型参数T,cast到了Trait上了。
Trait::Type,这个的用法,就是通过一个Trait,拿到它里面定义的
一个类型Type
我们的例子中,就是这个步骤:<T as Trait>::Currency
pub trait Trait: system::Trait {
type Currency: Currency<Self::AccountId>;
}
通过这个步骤,我们从Trait,拿到了里面的一个类型Currency。
最后一个,Trait<Type>,说的是,我们在使用一个带范型参数的Trait时,需要给其具体的范型类型。
在我们的例子中,Currency是带一个范型参数的Trait,定义在这里:https://github.com/paritytech/substrate/blob/f8935061c86b42f1018988166156ba792b0aa1a0/frame/support/src/traits.rs#L839
所以我们在把一个类型“<T as Trait>::Currency” as 成Currency(Trait)的时候,需要给Currency提供具体的类型参数
这个类型参数很长,就是里面的那一串:<T as system::Trait>::AccountId>
这样,经过:<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>
这个操作后,我们得到了Trait - Currency了。
最后一步的操作,还是:Trait::Type,从Trait - Currency中得到一个类型Balance。
Type as Trait
Trait::Type
Trait<Type>
这个三个逻辑,大家先记下来,看代码的多想一下,应该会很快熟悉。
ype BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
这句话定义了一个带范型参数T的类型BalanceOf,其具体定义如等号右边👉
红军大叔-学员:
另外, 感觉第三个看起来是Type<Trait> 而不是 Trait<Type> ?
徐杨-助教: Currency<T>里的Currency是trait。是这三个,最后一个到AccountId>结束。第一个是定义在Trait里面的type。
03
Li smith-学员:这个返回值应该是什么类型,同时考虑异常和传递结果。这里提示返回值不兼容?
王大锤-讲师:DispatchResultWithPostInfo是和weight相关的,看起来v好像和weight没啥关系。
Li smith-学员:我是看DispatchResult只能返回OK(())没参数,就用DispatchResultWithPostInfo了。
陈威-学员:返回全靠事件和错误。不能立刻返回,那是中心化的方式。
04
昊暠skyh-学员:Something get(fn something): Option<u32>;,u32和option<u32>有什么区别?实现和获取上好像是一样吧,在什么地方有区别呢?
大锤-讲师:比如有时候有些值虽然你没有set过,但是有初始值;比如u32是0,这样你就没法分清楚这个值有没有set过,但是如果你读出来的值是None就可以很清楚地知道这个值没有被set过。
陈威-学员:
pub xx get(fn xx): double_map T::xx, T::xx => Option<T::bb>;
for xx in <xx<T>>::iter_prefix(n) {}
https://github.com/paritytech/substrate/blob/dbf2163250833e6ac898e7f6c3c8f89f08a7c19d/frame/support/src/storage/generator/double_map.rs#L357
05
村上香菜子-学员:我看了turbofish的定义,基本上它的意思就是,编译器不能猜出来是什么类型的,我们就用turbofish来写。语法我也了解了。
有个事情想不清楚的,就是 Module<Test>和Module::<Test>::,这两种形式有什么区别?分别是在什么情况下用的?因为都是已经实例化了,在我看来,应该就是一回事吧?
比如说这个情况。我们在mock.rs上定义了pub type PoeModule = Module<Test>;
,然后在tests.rs上使用了:
assert_ok!(PoeModule::create_claim(Origin::signed(1), claim.clone()));
把它替换过来,其实相当于:
assert_ok!(Module<Test>::create_claim(Origin::signed(1), claim.clone()));
那这种情况也是属于调用具体某函数,也用的是Module<Test>,这个该怎么理解呢?
徐杨-助教:把它替换过来,其实相当于:
assert_ok!(Module<Test>::create_claim(Origin::signed(1), claim.clone()));
这个逻辑不是这样的,没法这么替换,这个语法:Module<Test>::create_claim,编译不通过的。
这里需要使用turbofish的语法来指定,这个地方是最终使用Module调用方法的地方。
Module<Test>,这个是在type redefinition的时候用吧
我们在做类型重定义的时候,可以按照着这个语法,例如:pub type System = system::Module<Test>;
村上香菜子-学员:好的明白了。我就记着,只要是定义,就是Module<Test>这样的语法定义,重定义也在定义的范围内,虽然我们已经将T实例化成Test了,但重定义终究是定义。如果是使用的时候,就用turbofish这种写法。我上面这种直接替换的模式是行不通的。
第一题
本次课程的第一题是编写测试案例,视频中已经演示了:创建存证、撤销存证的开发方法,留下一题:转移存证的测试用例,我们看看大致的思路
对于转移存证来讲,会有一个正确流程的test case,和n个错误流程的test case。我们先来看看正确流程的代码:
1、创建 2、转移 3、验证存证数据还在 4、验证存证的owner已经发生转移
1、ensure_signed出错 2、claim不存在 3、交易发起方不是claim的owner 4、接收方不存在
1、用户A为自己的存证X设置价格P1 2、用户B可以以某一个价格购买X,当出价P2大于等于P1时,B以P1的价格将费用转移给A,用户A将存证转移给B,同时将价格设置为P2。如果出价P2低于P1时,则购买失败,返回错误
1、Trait中定义Currency类型,一来为最终费用转移使用,二来定义BalanceOf类型 2、修改之前的create_claim函数,使得可以在创建claim时设置默认价格 3、添加新的update_price函数,修改claim的价格 4、添加新的buy_claim函数,实现购买功能,其中需要使用到Currency中的transfer
这是由一块链习和Parity出品,专为区块链技术爱好者量身打造的Substrate技术开发体验课。
课程采用班级群+小组学习制模式进行。由课程导师+助教+班长共同为用户提供服务,采用 15 人左右小组学习制,每位助教定向辅导一个小组并进行定向作业辅导、答疑等,确保更好的学习效果。
除了四位讲师,还有6位助教加入课程。所有助教均有一线区块链公司技术相关背景,并有Substrate技术实战经验,确保每一位开发者都能够得到更专业有效的指导。
第一期课程报名开启一周,100个席位全部抢占完。
第二期课程报名通道提前开放,已经有开发者率先占座。席位有限,报名请抓紧!
欢迎扫码了解更多和课程报名!
扫码关注公众号,回复“1”加入开发者社群