创造我们的NFT,使用Substrate 创建KItties 三_substrate 实现 nft_元苍子的博客-程序员宅基地

技术标签: Substrate  rust  区块链  去中心化  

可调度项、事件和错误

在本教程的上一节中,我们奠定了旨在管理小猫的所有权的基础 - 即使它们还不存在!在这一部分中,我们将通过使用我们声明的存储项目使我们的托盘能够创建Kitty来使用这些基础。稍微分解一下,我们将写:

  • create_kitty:一个可调度或可公开调用的函数,允许帐户铸造Kitty。
  • mint():一个辅助功能,用于更新托的存储项目并执行错误检查,由 调用。create_kitty
  • pallet Events: 使用 FRAME的#[pallet::event] 属性。

在本部分结束时,我们将检查所有内容是否编译无误,并使用外部PolkadotJS 应用程序 UI 调用我们的 create_kitty 。

公共和私人功能

在我们深入研究之前,了解我们将围绕 Kitty pallet的铸币和所有权管理功能进行编码的pallet设计决策是非常重要。

作为开发人员,我们希望确保我们编写的代码高效且优雅。 通常,针对一个进行优化会针对另一个进行优化。 我们将设置pallet以优化两者的方式是将“繁重”逻辑分解为私有辅助函数。 这也提高了代码的可读性和可重用性。 正如我们将看到的,我们可以创建可以由多个可调度函数调用的私有函数,而不会影响安全性。 事实上,以这种方式构建可以被认为是一种附加的安全功能。 查看这个关于编写和使用辅助函数的操作指南以了解更多信息。

在开始实施这种方法之前,让我们首先描绘一下组合可调度和辅助函数的样子。

create_kitty是一个可调度的功能或外在功能::

  • 检查源是否已签名
  • 使用签名帐户生成随机哈希
  • 使用随机哈希创建新的 Kitty 对象
  • 调用私有函数mint()

mint是一个私有助手函数,它:

  • 检查小猫咪是否不存在
  • 使用新的 Kitty ID 更新存储(适用于所有 Kitty 和所有者的帐户)
  • 更新存储和新所有者帐户的新小猫总数
  • 存入一个事件,以指示已成功创建小猫

编写可调度create_kitty

FRAME 中的可调度始终遵循相同的结构。 所有的pallet dispatchable 都存在于#[pallet::call] 宏下,该宏需要使用impl<T: Config> Pallet {} 声明dispatchables 部分。 阅读有关这些 FRAME 宏的文档以了解它们的工作原理。 这里我们需要知道的是,它们是 FRAME 的一个有用功能,可以最大限度地减少为将pallet正确集成到 Substrate 链的runtime所需编写的代码。

权重

根据其文档中描述的#[pallet::call] 的要求,每个可调度函数都必须具有关联的权重。 权重是使用 Substrate 开发的重要部分,因为它们提供了围绕计算量的安全防护,以在执行时适合块。

Substrate 的加权系统迫使开发人员在调用每个外部函数之前考虑其计算复杂性。 这允许节点考虑最坏情况的执行时间,避免因外部因素导致网络滞后,这些外部因素可能需要比指定的块时间更长的时间。 权重也与任何已签名外在的收费系统密切相关。

由于这只是一个教程,我们将默认所有权重为 100 以保持简单。

假设您现在已经用本节的帮助文件替换了pallets/kitties/src/lib.rs 的内容,找到ACTION #1 并使用以下行完成函数的开头:

#[pallet::weight(100)]
pub fn create_kitty(origin: OriginFor<T>) -> DispatchResult {
   
    
    let sender = ensure_signed(origin)?; // <- add this line
    let kitty_id = Self::mint(&sender, None, None)?; // <- add this line
    // Logging to the console
    log::info!("A kitty is born with ID: {:?}.", kitty_id); // <- add this line

    // ACTION #4: Deposit `Created` event

    Ok(())
}

我们不会进行调试,但登录到控制台是一个有用的提示,可确保您的托盘按预期运行。 为了使用 log::info,将其添加到您的托盘的 Cargo.toml 文件中。

编写函数mint()

正如我们在上一节中编写create_kitty时所看到的,我们需要创建mint(),以便将我们新的唯一Kitty对象写入本教程第二部分中声明的各种存储项。

让我们直接开始吧。我们的mint()函数将采用以下参数:

  • owner: &T::AccountId
  • dna: Option<[u8; 16]>
  • genderOption<Gender>

它将返回Result<T::Hash, Error<T>>

粘贴以下代码片段以编写mint函数,取代工作代码库中的ACTION #2:

// Helper to mint a Kitty.
pub fn mint(
    owner: &T::AccountId,
    dna: Option<[u8; 16]>,
    gender: Option<Gender>,
) -> Result<T::Hash, Error<T>> {
   
    
    let kitty = Kitty::<T> {
   
    
        dna: dna.unwrap_or_else(Self::gen_dna),
        price: None,
        gender: gender.unwrap_or_else(Self::gen_gender),
        owner: owner.clone(),
    };

    let kitty_id = T::Hashing::hash_of(&kitty);

    // Performs this operation first as it may fail
    let new_cnt = Self::count_for_kitties().checked_add(1)
        .ok_or(<Error<T>>::CountForKittiesOverflow)?;

    // Check if the kitty does not already exist in our storage map
    ensure!(Self::kitties(&kitty_id) == None, <Error<T>>::KittyExists);

    // Performs this operation first because as it may fail
    <KittiesOwned<T>>::try_mutate(&owner, |kitty_vec| {
   
    
        kitty_vec.try_push(kitty_id)
    }).map_err(|_| <Error<T>>::ExceedMaxKittyOwned)?;

    <Kitties<T>>::insert(kitty_id, kitty);
    <CountForKitties<T>>::put(new_cnt);
    Ok(kitty_id)
}

让我们来看看上面的代码在做什么。

我们正在做的第一件事就是创建一个新的Kitty对象。然后,我们使用基于kitty当前属性的哈希函数创建一个唯一的kitty_id

接下来,我们使用存储获取器函数Self::count_for_kitties()增加CountForKitties。我们还在检查check_add()函数的溢出。

我们最后的验证是确保 kitty_id 不存在于我们的 Kitties StorageMap 中。 这是为了避免任何可能的哈希键重复插入。

一旦我们的支票通过,我们就会通过以下方式更新我们的存储项目:

  1. 利用try_mutate更新小猫的主人vector。
  2. 使用insertSubstrate的StorageMap API提供的方法,用于存储实际的Kitty对象并将其与其kitty_id相关联。
  3. 使用put由StorageValue API提供,用于存储最新的Kitty计数。

快速回顾我们的存储项目

  • <Kitties<T>>:通过存储Kitty对象并将其与其Kitty ID相关联,存储Kitty的独特特征和价格。
  • <KittyOwned<T>&g
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41394488/article/details/124646568

智能推荐

Hbuilder编辑器怎么用 使用方法(wap静态页面测试)_hbuilder加页面,怎么生效-程序员宅基地

HBuilder不仅仅提示全面的语法,非语法的各种候选输入也都能提示。包括图片、链接、颜色、字体、脚本、样式、URI、ID、class、自定义JS对象、方法。小编在本文详细介绍了Hbuilder编辑器的使用方法。Q:怎么才能快速掌握HBuilder开发技巧?A:软件自带HelloHBuilder项目,该项目为教程项目(如果不小心删除了不要担心,可以在新建WEB项目时,使用HelloHBuild_hbuilder加页面,怎么生效

2020年6月六级作文和翻译三国演义_2020年6月六级翻译作文-程序员宅基地

这两篇难度不大,很容易得到一个过线的分数。Directions: For this part, you are allowed 30 minutes to write an essay on the saying The best preparation for tomorrow is doing your best today. You should write at least 150 words but no more than 200 words.《三国演义》(The Romance ._2020年6月六级翻译作文

软件测试工程师到软件测试开发工程师,我需要学什么-程序员宅基地

做了将近3年软件测试,部分测试开发的经验,也做了近1年管理的测试组长,但是还是希望往技术更深方面发展。于是列个技能清单,以此为目标,只为努力实现,成为一名测试开发工程师。1、测试开发工程师,毕竟也是测试人员,基础的测试理论是必须熟悉与掌握,包括黑盒测试、白盒测试以及等价类、边界值等设计测试用例方法等。实践:最基本熟读《软件测试》一书2、通过编写代码写自动化测试用例、写测试框架和工具,一..._软件测试师好还是java软件开发工程师好

Mbed CLI 简介_mbed cl1安装后使用-程序员宅基地

MbedOS 的在线Mbed编译环境实现使用浏览器进行Mbed 的云端开发。对于初学者而言这是十分方便的,免去了许多开发环境的安装和配置,而且能方便地实现软件更新和发布,分享。但是在线编译也有不足之处,就是有时候网络太不给力了。另外,源代码只能在Mbed 的社区中分享。不能发布到github。如果不使用在线编译,你可以有两个选择:1 在线编译环境中建立应用程序的代码,然后..._mbed cl1安装后使用

Windows下开启Mysql慢查询_windowsmysql慢查询的开启-程序员宅基地

Windows下开启Mysql慢查询第一步:修改my.ini(mysql配置文件) 在my.ini中加上下面两句话log-slow-queries= “D:\wamp\mysql_slow_query.log”long_query_time=0.0001 第一句使用来定义慢查询日志的路径(因为是windows,所以不牵涉权限问题) 第二句使用来定义查过多少秒的查询算是慢查询,我..._windowsmysql慢查询的开启

Hynix-China 2011始务式-新征程的号角已吹响-程序员宅基地

今天,公元2011年1月4日,元旦休假后第一天上班,很多韩国公司照例新年第一天要进行始务式,顾名思义就是新年开工仪式。参加完这样一个仪式后,我个人感觉精神上非常充实,收获也颇多。 首先说说始务式吧,得从12月31日说起,今天我做公司年度优秀员工届时将会有一个授奖仪式,人事部要求做一些彩排工作,这时我本人以为始务式上就是总经理发表讲话及授奖等简单的一两个环节。谁知道正式开始后感受到的却远不止这些。 始务式一开始就是一段四物社团同事的表演,之后就是一段影响

随便推点

SVN使用经验心得三-程序员宅基地

21、将所有的开发代码存放在trunk上。 常用分支模式: a、发布分支:在代码发展到一定阶段,建立发布分支,将当前的一个版本取出来,拷贝到branches目录下,进行全面严酷的测试,如发现BUG则在当前版本进行修复,并同步更新trunk中的BUG,经测试完成后,将文件拷贝到tags目录中发布,并提交给客户。 b、特性分支:如果需要作复杂的修改,会影响到trun

编程:编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC_.编写一个截取字符串的函数,任意输入一个字符串和字节数,返回该字符串的指定-程序员宅基地

代码如下:package test; class SplitString{ String SplitStr; int SplitByte; public SplitString(String str,int bytes) { SplitStr=str; SplitByte=bytes; System.out.println("The Stringis_.编写一个截取字符串的函数,任意输入一个字符串和字节数,返回该字符串的指定

Keras之查看模型layer的层数_查看模型的层数-程序员宅基地

当模型很大的时候有时候需要查看模型某个layer对应的层数. 用model.summary()不大好使.可以用如下代码列举模型的层数:{i: v for i, v in enumerate(model.layers)}{0: <keras.layers.convolutional.Conv2D at 0x7f182bcd1710>, 1: <keras.layers.normalization.BatchNormalization at 0x7f1840981828>, _查看模型的层数

Postman页面介绍-程序员宅基地

1.左边面板为请求的历史与 history和请求集合collections(为达到某一功能而将多个请求放在一个集合里面)参数也就是跟着接口文档来,没有什么特别的2.很多接口工具都可以用来测试接口,为什么我们要选择postman呢,那当然是有一些postman的方便与好处了2.1postman可以设置变量,环境变量和全局变量环境变量,顾名思义,环境变量是可以区分环境的变量,一般在工作中,测试环境都不..._postman页面介绍

Unsatisfied dependency expressed through field ‘orderService‘; 启动类mapperscan-程序员宅基地

报错 org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderController': Unsatisfied dependency expressed through field 'orderService'; nested exception is原因:启动类没有加//@MapperScan("com.atguigu.eduorder....