Mapping 数据结构 | 用 Rust 写智能合约(二)

这篇文章主要介绍了Mapping 数据结构 | 用 Rust 写智能合约(二) ,文中通过代码以及文档配合进行讲解,很详细,它对在座的每个人的研究和工作具有很经典的参考价值。 如果需要,让我们与区块链资料网一起学习。

https://www.interchains.cc/21383.html

Mapping 数据结构 | 用 Rust 写智能合约(二)是很好的区块链资料,他说明了区块链当中的经典原理,可以给我们提供资料,Mapping 数据结构 | 用 Rust 写智能合约(二)学习起来其实是很简单的,

不多的几个较为抽象的概念也很容易理解,之所以很多人感觉Mapping 数据结构 | 用 Rust 写智能合约(二)比较复杂,一方面是因为大多数的文档没有做到由浅入深地讲解,概念上没有注意先后顺序,给读者的理解带来困难

Mapping 数据结构 | 用 Rust 写智能合约(二)

  • FISCO BCOS
  • 狗哥
  • 联盟链
  • 智能合约
  • Rust
  • WASM

TryTry Liquid,很不错!

在上一篇中,我们讲到了如下知识点:

  • 什么是WASM合约
  • 标准ink!合约模板
  • ink!实现值的读取

今天我们来讲讲用Mapping的方式进行值的存储与读取。

不过,我们这次不基于Substrate,而是基于FISCO BCOS新推出Liquid智能合约——Liquid智能合约同样也是基于RUSTWASM

1 Liquid 环境配置

如下内容来自官方文档:

https://liquid-doc.readthedocs.io/zh_CN/latest/docs/quickstart/prerequisite.html

部署 Rust 编译环境

Liquid 智能合约的构建过程主要依赖 Rust 语言编译器rustc及代码组织管理工具cargo,且均要求版本号大于或等与 1.50.0。如果此前从未安装过rustccargo,可参考下列步骤进行安装:

  • 对于 Mac 或 Linux 用户,请在终端中执行以下命令;

    # 此命令将会自动安装 rustup,rustup 会自动安装 rustc 及 cargo curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • 对于 32 位 Windows 用户,请从此处下载安装 32 位版本安装程序。
  • 对于 64 位 Windows 用户,请从此处下载安装 64 位版本安装程序。

如果此前安装过rustccargo,但是未能最低版本要求,则可在终端中执行以下命令进行更新:

rustup update

安装完毕后,分别执行以下命令验证已安装正确版本的 rustccargo

rustc --version cargo --version

此外需要安装以下工具链组件:

rustup toolchain install nightly rustup target add wasm32-unknown-unknown --toolchain stable rustup target add wasm32-unknown-unknown --toolchain nightly rustup component add rust-src --toolchain stable rustup component add rust-src --toolchain nightly

构建 Liquid 智能合约的过程中需要下载大量第三方依赖,若当前网络无法正常访问 crates.io 官方镜像源,则按照以下步骤为 cargo 更换镜像源:

# 编辑cargo配置文件,若没有则新建 vim $HOME/.cargo/config

并在配置文件中添加以下内容:

[source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" replace-with = 'ustc' [source.ustc] registry = "git://mirrors.ustc.edu.cn/crates.io-index"

最关键的是要安装cargo-liquid

cargo install --git https://gitee.com/WeBankBlockchain/cargo-liquid --tag v1.0.0-rc1 --force

2 创建一个 liquid 项目

执行如下命令:

cargo liquid new map_storer

创建完成后进入文件夹:

cd map_storer

3 替换代码

lib.rs内容用如下代码替换:

#![cfg_attr(not(feature = "std"), no_std)]  use liquid::storage; use liquid_lang as liquid;  #[liquid::contract] mod map_storer {     use super::*;      /// Defines the state variables of your contract.     #[liquid(storage)]     struct MapStorer {         my_number_map: storage::Mapping<address, u32>,     }      /// Defines the methods of your contract.     #[liquid(methods)]     impl MapStorer {         /// Defines the constructor which will be executed automatically when the contract is         /// under deploying. Usually constructor is used to initialize state variables.         ///          /// # Note         /// 1. The name of constructor must be `new`;         /// 2. The receiver of constructor must be `&mut self`;         /// 3. The visibility of constructor must be `pub`.         /// 4. The constructor should return nothing.         /// 5. If you forget to initialize state variables, you          ///    will be trapped in an runtime-error for attempting          ///    to visit uninitialized storage.         /// Constructor that initializes the `my number map` Hashmap         pub fn new(&mut self) {             self.my_number_map.initialize();         }         // Get the value for a given addr         pub fn get(&self, of: address) -> u32 {             self.my_number_or_zero(&of)         }          // Set the value for a given addr         pub fn store(&mut self, payload: u32, of: address) {             self.my_number_map.insert(&of, payload);         }          // Get the value for the calling addr         pub fn get_my_number(&self) -> u32 {             let caller = self.env().get_caller();             self.my_number_or_zero(&caller)         }          // Returns the number for an addr or 0 if it is not set.         fn my_number_or_zero(&self, of: &address) -> u32 {             let value = self.my_number_map.get(of).unwrap_or(&0);             *value         }     }      /// Unit tests in Rust are normally defined within such a `#[cfg(test)]`     /// module and test functions are marked with a `#[test]` attribute.     /// The below code is technically just normal Rust code.     #[cfg(test)]     mod tests {         /// Imports all the definitions from the outer scope so we can use them here.         use super::*;     } }

4 测试与编译

cargo +nightly test cargo +nightly liquid build

Mapping 数据结构 | 用 Rust 写智能合约(二)

ABI 和 Solidity ABI 保持一致!这点很好:

Mapping 数据结构 | 用 Rust 写智能合约(二)

5 部署

5.1 安装 FISCO BCOS 区块链blockchainliquid分支

当前,FISCO BCOS 对 Wasm 虚拟机的支持尚未合入主干版本,仅开放了实验版本的源代码及可执行二进制文件供开发者体验,因此需要按照以下步骤手动搭建 FISCO BCOS 区块链blockchain

  1. 根据依赖项说明中的要求安装依赖项;
  2. 下载实验版本的建链工具 build_chain.sh:

    cd ~ && mkdir -p fisco && cd fisco curl -#LO https://gitee.com/WeBankBlockchain/liquid/attach_files/651253/download/build_chain.sh && chmod u+x build_chain.sh
  3. 使用 build_chain.sh 在本地搭建一条单群组 1 节点的 FISCO BCOS 区块链blockchain并运行。更多 build_chain.sh 的使用方法可参考其使用文档:

    注:可通过把build_chain.sh中令Download_link=cdn_download_link来提速

    Mapping 数据结构 | 用 Rust 写智能合约(二)

    bash build_chain.sh -l 127.0.0.1:1 -p 30300,20200,8545 bash nodes/127.0.0.1/start_all.sh

    Mapping 数据结构 | 用 Rust 写智能合约(二)

5.2 部署 Node.js SDK

由于 Liquid 当前暂为实验项目,因此目前仅有 FISCO BCOS Node.js SDK 提供的 CLI 工具能够部署及调用 Liquid 智能合约。Node.js SDK 部署方式可参考其官方文档。但需要注意的是,Liquid 智能合约相关的功能目前同样未合入 Node.js SDK 的主干版本。因此当从 GitHub 克隆了 Node.js SDK 的源代码后,需要先手动切换至liquid分支并随后安装SCALE编解码器:

git clone https://gitee.com/FISCO-BCOS/nodejs-sdk.git cd nodejs-sdk && git checkout liquid  npm install  cd packages/cli/scale_codec && npm install

返回cli目录:

cd ..

将证书文件复制到cli/conf/authentication文件夹中:

cp ~/fisco/nodes/127.0.0.1/sdk/* ./ # 根据实际地址调整

测试SDK连通性:

./cli.js exec getBlockNumber

Mapping 数据结构 | 用 Rust 写智能合约(二)

5.3 将合约部署至区块链blockchain

使用 Node.js SDK CLI 工具提供的deploy子命令,我们可以将 Hello World 合约构建生成的 Wasm 格式字节码部署至真实的区块链blockchain上,deploy子命令的使用说明如下:

cli.js exec deploy <contract> [parameters..]  Deploy a contract written in Solidity or Liquid  Positionals:   contract    The path of the contract                       [string] [required]   parameters  The parameters(split by space) of constructor                                                            [array] [default: []]  Options:   --version   Show version number                                      [boolean]   --abi, -a   The path of the corresponding ABI file                    [string]   --who, -w   Who will do this operation                                [string]   -h, --help  Show help                                                [boolean]
/cli.js exec deploy /Users/liaohua/substrate/contracts/liquid/map_storer/target/map_storer.wasm --abi /Users/liaohua/substrate/contracts/liquid/map_storer/target/map_storer.abi

部署成功后,返回如下形式的结果,其中包含状态码、合约地址及交易哈希:

{     "status": "0x0",     "contractAddress": "0x039ced1cd5bea5ace04de8e74c66e312ba4a48af",     "transactionHash": "0xf84811a5c7a5d3a4452a65e6929a49e69d9a55a0f03b5a03a3e8956f80e9ff41" }

Mapping 数据结构 | 用 Rust 写智能合约(二)

5.4 调用

使用 Node.js SDK CLI 工具提供的call子命令,我们可以调用已被部署到链上的智能合约,call子命令的使用方式如下:

cli.js exec call <contractName> <contractAddress> <function> [parameters..]  Call a contract by a function and parameters  Positionals:   contractName     The name of a contract                    [string] [required]   contractAddress  20 Bytes - The address of a contract      [string] [required]   function         The function of a contract                [string] [required]   parameters       The parameters(split by space) of a function                                                            [array] [default: []]  Options:   --version   Show version number                                      [boolean]   --who, -w   Who will do this operation                                [string]   -h, --help  Show help                                                [boolean]

先调用get_my_number函数,这个参数无需输入值:

./cli.js exec call map_storer 0xf5736213670d32f63b1a598e55753014f710344e get_my_number

Mapping 数据结构 | 用 Rust 写智能合约(二)

再调用store函数,对地址0x039ced1cd5bea5ace04de8e74c66e312ba4a48af进行存值:

./cli.js exec call map_storer 0xf5736213670d32f63b1a598e55753014f710344e store 300 0x039ced1cd5bea5ace04de8e74c66e312ba4a48af

Mapping 数据结构 | 用 Rust 写智能合约(二)

调用get函数,对上述地址进行取值:

./cli.js exec call map_storer 0xf5736213670d32f63b1a598e55753014f710344e get 0x039ced1cd5bea5ace04de8e74c66e312ba4a48af

Mapping 数据结构 | 用 Rust 写智能合约(二)

成功~

6 源码解读

6.1 Mapping 类型

相对于上一篇的代码,本篇中的代码引入了新的类型——Mapping

Mapping是一种很有用的类型,我们在Solidity合约中同样能见到它的身影:

如:

mapping(address=>bool) isStake;

liquid智能合约中,我们这样定义一个Mapping

my_number_map: storage::Mapping<address, u32>,

Mapping变量的get操作:

let value = self.my_number_map.get(of).unwrap_or(&0);

Mapping变量的insert操作:

self.my_number_map.insert(&of, payload);

6.2 获取当前合约调用者

let caller = self.env().get_caller();

6.3 unwrap_or

unwrap_orRust错误捕捉方式的一种:

fn unwrap_or<T>(option: Option<T>, default: T) -> T {     match option {         None => default,         Some(value) => value,     } }

unwrap_or提供了一个默认值default,当值为None时返回default

因此,如下语句中,当of对应的值不存在时,便会返回0

let value = self.my_number_map.get(of).unwrap_or(&0);

部分转自网络,侵权联系删除www.interchains.cchttps://www.interchains.cc/21383.html

区块链毕设网(www.interchains.cc)全网最靠谱的原创区块链毕设代做网站 部分资料来自网络,侵权联系删除! 最全最大的区块链源码站 ! QQ3039046426
区块链知识分享网, 以太坊dapp资源网, 区块链教程, fabric教程下载, 区块链书籍下载, 区块链资料下载, 区块链视频教程下载, 区块链基础教程, 区块链入门教程, 区块链资源 » Mapping 数据结构 | 用 Rust 写智能合约(二)

提供最优质的资源集合

立即查看 了解详情