查看原文
其他

Sub Dev 讨论 | Pallet 之间动态调用方法最新进展

胡键 一块Plus社区 2020-11-11

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


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



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


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


Q&A
社区问答精选


01

昊暠skyh-学员:substrate 使用rpc调用extrincs的例子或者文档有吗?

 

陈锡亮-讲师:

https://polkadot.js.org/api/substrate/rpc.html#submitandwatchextrinsic-extrinsic-extrinsic-extrinsicstatus

polkadot apps检查元素看network ws可以看具体怎么交互的。

 

02

Lam007-学员:

 

程剑宇 - 助教:这是parathread,parachain是常连的,通过slot竞拍。parathread是需要时连,按使用付费。

 

Lam007-学员:就是说relay chain连接点是有数量限制的,而parachains通过竞拍(付费),成为常连chain。

 

而relay chain 也会预留一些连接点给parathread,以便parathread有需要时付费连接。

 

程剑宇 - 助教:是的。

 

Lam007-学员:任何parachain都能成为一个relaychain,但是它可以选择免费接入,是吗?

 

程剑宇 - 助教:relaychain只有一个。

 

Lam007-学员:relay chain外围的parachain也可以再接一层parachain,那么第一层的parachain就可以作为外一层parachain的relay chain。

 

程剑宇 - 助教:嗯sub relay吧,不过感觉这个还要挺久的。

 

03

红军大叔-学员:

 

这块metadata和balance模块下的讲解, 提到calls对应到decl_module下的const 常量, 听不懂, 想表达什么意思呢?现在大致理解的是:模块宏下面的内容, 会暴露给metadata, metadata的作用是给前端使用?

 

陈威-学员:

pub fn transfer(

origin,

dest: <T::Lookup as StaticLookup>::Source,

#[compact] value: T::Balance

)

这些信息和上面的注释会放到metadata的call里面。const ExistentialDeposit: T::Balance = T::ExistentialDeposit::get();

 

这是常量, 不放到calls, 放到constants。

 

每个模块的元素都集中到metadata, 前端就可以, 通过这个知道, 每个模块的calls, errors, constants, events

 

比如一个错误出现, 前端扫描块时只能得到一个序号, 根据metadata转换后可以得到err的描述, 和err的名字. 

 

// retrieve and log the complete metadata of your node

let a = await api.rpc.state.getMetadata();

a = a.toJSON();

console.log(JSON.stringify(a, null, 2));

 

陈锡亮-讲师:decl_module里面除了calls也可以放constants,之所以用宏搞的这么麻烦主要就是为了可以自动生成metadata暴露给前端,前端可以通过这些信息知道如何于链交互。

 

04

红军大叔-学员:判断溢出,生产环境有没有类似atom的原子方式保护?比如上述代码方式, 存不存在并发引起的问题?

 

WJY-学员:怎么会并发呢?

 

陈威-学员:原子操作是多线程用的。并且不是处理溢出的。区块链里面是顺序处理交易。

 

WJY-学员:多线程现在还在幻想当中,现在都是顺序处理 所以都是慢慢累加。

 

廖师虎-学员:事件不会乱序吗?不同节点的事务池,事务条目可能不同

 

WJY-学员:顺序不用管啊 ,我觉得合理就打包,想象它就是一台机器的工作。加入链中的区块是需要进一步共识的 ,最终都一样,就是不同节点你有不同出块可以 但是没关系 最终我们会达成共识用哪个。

 

红军大叔-学员:这么说, 区块链在并发方面其实倒是简单了?回顾下, 好像也确实只有在dag的时候提到并发, 其他是都是顺序的。

 

WJY-学员:是的,现在几乎所有都是副本模式嘛 所有机器干同样工作。不是竞争关系。

 

05

没得-学员:

有没有大哥知道这个怎么实现啊?用range和迭代器实现阶乘。

 

洋芋-助教:这个试下呢,

https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.product

 

06

raindust-学员:请问pallet之间有什么方法可以互相调用吗?我目前所知的方式只有使用一个pallet的Trait继承另一个pallet的Trait。

 

陈威-学员:关联类型,或者从你的Trait的泛型参数传入。

 

陈锡亮-讲师:有什么需求你要动态调用,可以参考pallet-scheduler。

 

raindust-学员:我在想有没有可能在不同的pallet的下层假设一个message bus以增加节点的可伸缩性,所以想先了解一下相关的原理。

 

陈锡亮-讲师:polkadot 目前正常尝试实现一套新的框架用于xcmp,其中也有一套message bus的设计,未来也可能也会提供给substrate使用。可以听听看 https://www.crowdcast.io/e/polkadefi-conference/1

 

陈威-学员:你要pallet发出消息,其他pallet接收?

 

raindust-学员:是的,类似于这样,如果这样可以实现,就可以了在中间放一个消息队列了,如果是加了message bus就会希望一个小的集群代表一个节点工作,我是想让substrate应用在联盟链方向。


 

作业点评
第四、五课作业

第四课

题目要求

  1. 算出指定档案的 hash + 不超过 255 长度的 note
  2. 将以上内容以 signed tx 方式传给 Substrate 保存
解题思路
node 部分的逻辑与之前课程作业的【创建存证】部分的逻辑一样,不同之处在于增加了 note。因此,最简单的做法就是在原有的 create_claim 基础上进行相应地修改:
  1. 增加 note 的最大长度定义
  2. 仿造原有的 proof 的定义,在其基础上增加 note 字段
  3. 仿造 create_claim 函数,增加 create_claim_with_note,增加 note 参数,以及相应的长度验证逻辑,其余照旧。
  4. 事件复用之前的 ClaimCreated 就好了。
优秀作业
在检查作业的过程中,发现有些同学给出了更好的一些示范:
  1. create_claim_with_note 中传入的参数为 Option\
    ,这个比较符合实际情况,因为用户确实有可能不输入 note。
  2. 在 map 中考虑了时戳,这样整个结构就变成了下面的样子,更加人性化。
  1. ProofHash2Detail: map hasher(blake2_128_concat)Vec<u8>=>(T::AccountId, T::BlockNumber, T::Moment,Option<Vec<u8>>);
大家有兴趣的话可以参考这里:
https://github.com/jsrzx/team1/blob/31d63d979d13009eb1abe02aa910cfeb38572fa1/lesson4/substrate-node-template/pallets/poe/src/lib.rs
2a) 前端 ui 可以输入 note 并在成功插入之后显示相应的信息。整个过程基本上也和上一个作业的做法类似,主要变化:
  1. 增加 note 的输入框,以及配套的状态设置函数。
  2. 添加事件监听函数,以便在成功创建之后显示相应信息。
  3. 修改提交部分的代码,将其替换成 node 中相应的实现函数,以及在输入中加入 note 参数。
基本还是以 react 编程为主,这里不再赘述。同样,以我们组的代码作为示范来展示:https://github.com/jsrzx/team1/blob/31d63d979d13009eb1abe02aa910cfeb38572fa1/lesson4/substrate-front-end-template/src/PoeModule.js
2b) 要实现的目的跟 2a) 一样,只是改用 node.js client + polkadot-api.js 方式直接跟 node 进行交互。lesson4 下 client/src/script.js 基本上已经是具备基本雏形,只需按照注释填写代码即可。几点注意:
  1. 向 node 发起 extrinc 的格式:api.tx.\
    .\,若是查询的话,则 api.tx => api.query。\>\>
  • 比如:api.tx.poeModule.createClaimWithNote(hasher, comment).signAndSend(alice)
  • 读文件使用 node 的 fs.readFileSync,对于本题来讲,同步读会让编码简单一些。
  • hash 使用 readme 中建议的 @polkadot/util-crypto 内的 blake2,从这个测试中可以找到对应的使用例子:https://github.com/polkadot-js/common/blob/master/packages/util-crypto/src/blake2/asHex.spec.ts
  • 熟悉 promise 概念,与 node 打交道时基本都是 async/await 方式。
  • 整个代码类似:
    const api = await connect();let content = fs.readFileSync(filePath, 'utf-8');let hasher = blake2AsHex(content);const keyring = new Keyring({ type: 'sr25519' });const alice = keyring.addFromUri('//Alice');const hash = await api.tx.poeModule.createClaimWithNote(hasher, comment).signAndSend(alice);console.log('done with hash: ', hash);

    附加题
    在上题基础上,通过 account id 就能获得上题中的输入:文件 hash、blocknumber、note,因为用户可能上传多次,因此返回的应该是是一个数组。
    解题思路
    为了获得每个 account id 的这些信息,需要先将其记录下来,然后才能通过查询获得。需要对上题中的 node 逻辑进行改造:
    • 在创建的同时,将其记录到另一个以 account id 为 key 的 map 中,其 value 则是对应的输入。
    同样的,整个过程如下:
    1. 增加一个 map 用来记录相关信息
    2. 在上面的 create_claim_with_note 中记录其输入
    详细情况可以参考上面的代码链接。
    对于查询方式,与上题一样:一种通过 ui;一种通过 node.js client。除了 ui 方式需要 react 编程外,查询部分的代码基本相同:先通过 id 获得 claim 列表,再遍历获得细节。
    因为,这里是查询方法,故使用:api.query.\.\来获得内容。对于 ui 方式的实现同样可以参考前面的链接。\>
    第五课
    主要考察代码的重构和 rust 语法的熟悉。

    题目要求
    作业1:实现 random_value
    fn random_value(sender: &T::AccountId) -> [u8; 16] { let payload = ( T::Randomness::random_seed(), &sender, <frame_system::Module<T>>::extrinsic_index(),); payload.using_encoded(blake2_128)}
    作业 2:实现 insert_kitty
    1. fn insert_kitty(owner:&T::AccountId, kitty_id: T::KittyIndex, kitty:Kitty){
    2. Kitties::<T>::insert(kitty_id, kitty);
    3. KittiesCount::<T>::put(kitty_id +1.into());

    4. let user_kitties_id =Self::owned_kitties_count(&owner);
    5. // 注意这里的是通过 account_id 和 索引来得到对应的 kitty id,故如此
    6. <OwnedKitties<T>>::insert((owner.clone(), user_kitties_id), kitty_id);
    7. <OwnedKittiesCount<T>>::insert(owner, user_kitties_id +1);
    8. }
    作业 3:补全 create,直接引用刚刚实现的 insert
    1. Self::insert_kitty(sender, kitty_id, kitty);
    同样推荐我们组的代码范本:https://github.com/jsrzx/team1/tree/lesson-5/lesson5


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

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


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


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



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

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


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



    更多阅读:
    100位开发者已加入的Substrate课程导读视频奉上
    | 终于来了!Parity官方多位核心导师联合授课,Substrate技术爱好者速戳!
    Sub Dev 分享 | Polkadot进入NPoS,质押奖励如何分配

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


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

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