查看原文
其他

Sub Dev 讨论 | 看完 Rust 功力瞬间提高一层

徐杨 一块Plus社区 2020-11-11

一块链习是首家区块链技术学习社区,提供最系统的区块链技术课程学习,定期出品有深度的技术观察 + 评论。


《从0到一学会Substrate 区块链应用开发》由一块链习和Parity官方联合出品,专为区块链技术爱好者量身打造,并由 王大锤,陈锡亮,孙凯超,朱振明四位老师联合授课



目前第一期课程已经进行到第三周,同学们会在班级群讨论学习中遇到的难题或不解。另外每周日上午 10 点,都会进行课程内容知识拓展——作业点评会和在线答疑。


现在将第二周班级群日常优质的讨论内容和徐杨助教对第三课的作业点评分享给大家。


Q&A
社区问答精选

01

陈威-学员:请问一下,多签的搜集过程是怎么样的?


王晓玮-助教: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. 1、创建
  2. 2、转移
  3. 3、验证存证数据还在
  4. 4、验证存证的owner已经发生转移

这n个错误流程,就对应了transfer_revoke函数中每一个异常情况。我们先来看看transfer_revoke的代码,如下:


基本上每一个ensure和每一个?,都对应了一个错误流程的案例,那么这里就包括了:
  1. 1、ensure_signed出错
  2. 2、claim不存在
  3. 3、交易发起方不是claim的owner
  4. 4、接收方不存在

其中2、3是我们核心的业务逻辑需要cover的地方,我们来看看这两个的测试案例代码。

claim不存在的测试案例:


这个案例很简单,直接发起一个不存在的存证的转移,验证错误类型即可

交易发起方不是claim的owner,对应的测试案例:


这个也比较简单,调用transfer从不同的account去发起,进而触发错误。

第二题

转移存证的UI


首先添加一个state:AccountId,和它的setter函数


然后添加一个输入框,用来输入transfer到的账户信息;其onChange的定义,表明输入框有变化之后,调用AccountId的setter函数为其赋值


最后,添加一个按钮,点击会调用transferClaim接口,入参是digest & AccountId

附加题

这个是一道附加题:
  1. 1、用户A为自己的存证X设置价格P1
  2. 2、用户B可以以某一个价格购买X,当出价P2大于等于P1时,B以P1的价格将费用转移给A,用户A将存证转移给B,同时将价格设置为P2。如果出价P2低于P1时,则购买失败,返回错误

经过一些分析,我们需要做以下四个步骤:
  1. 1、Trait中定义Currency类型,一来为最终费用转移使用,二来定义BalanceOf类型
  2. 2、修改之前的create_claim函数,使得可以在创建claim时设置默认价格
  3. 3、添加新的update_price函数,修改claim的价格
  4. 4、添加新的buy_claim函数,实现购买功能,其中需要使用到Currency中的transfer

首先,我们看看Trait中,如何添加Currency类型


在lib.rs中,添加Currency trait的引用


在Trait中,添加Currency类型


在runtime的lib.rs中,impl poe::Trait for Runtime里,将类型Currency定义为balances Module,这是因为balances Module实现了Currency trait

balances Module实现Currency的代码在这里,Currency trait的定义在这里

还有,我们需要定义一个BalanceOf类型,以便后面定义price变量使用:


关于这个类型定义的分析,我之前在群里写过一些,同学们可以去翻看一下

大致思路是,这里面有三个逻辑:
Type as Trait
Trait::Type
Trait<Type>

将上面三个逻辑叠加使用,就可以有各种用法了。

第二步,添加一个新的StorageMap,保存claim与Balance的map


修改之前的create_claim函数,为每个新建的claim设置价格为零


在保存存证的同时,将存证的price - 0也一同保存
最后发送的事件,也添加了price的数据

第三步,添加新的update_price函数,修改claim的价格


第四步,我们来实现buy_claim函数


最前面是三个ensure的逻辑,分别判断claim是否存在、发送者是否是owner、价格是否超过owner设置的价格


然后,我们调用了T::Currency的transfer方法,sender将费用转给owner

注意,这个transfer是有可能失败的,例如钱不够,所以这个语句需要在所有更新状态语句的最前面,放在在第一句

后面更新了proofs和prices两个map。


“疑问有人解答,作业有人讲解批改,这是什么课程?”

这是由一块链习和Parity出品,专为区块链技术爱好者量身打造的Substrate技术开发体验课


课程采用班级群+小组学习制模式进行。由课程导师+助教+班长共同为用户提供服务,采用 15 人左右小组学习制,每位助教定向辅导一个小组并进行定向作业辅导、答疑等,确保更好的学习效果。


除了四位讲师,还有6位助教加入课程。所有助教均有一线区块链公司技术相关背景,并有Substrate技术实战经验,确保每一位开发者都能够得到更专业有效的指导。



第一期课程报名开启一周,100个席位全部抢占完。

第二期课程报名通道提前开放,已经有开发者率先占座。席位有限,报名请抓紧!


欢迎扫码了解更多和课程报名!



更多阅读:
100位开发者已加入的Substrate课程导读视频奉上
终于来了!Parity官方多位核心导师联合授课,Substrate技术爱好者速戳!
Sub Dev 分享 | Substrate Based区块链上线实战经验

扫码关注公众号,回复“1”加入开发者社群


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存