中移链合约常用开发介绍 (二)多索引表的使用

这篇具有很好参考价值的文章主要介绍了中移链合约常用开发介绍 (二)多索引表的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、目的

本文详细介绍了开发、部署和测试一个地址簿的智能合约的流程,适用于EOS的初学者了解如何使用智能合约实现本地区块链上数据的持久化和对持久化数据的增删改查。

二、智能合约介绍

区块链作为一种分布式可信计算平台,去中心化是其最本质的特征。每笔交易的记录不可篡改地存储在区块链上。智能合约中定义可以在区块链上执行的动作action和交易transaction的代码。可以在区块链上执行,并将合约执行状态作为该区块链实例不可变历史的一部分。

因此,开发人员可以依赖该区块链作为可信计算环境,其中智能合约的输入、执行和结果都是独立的,不受外部影响。

三、术语解释

EOS

EOS是Enterprise Operation System的缩写,是商用分布式应用设计的一款区块链操作系统。EOS引入了一种新的区块链架构EOSIO,用于实现分布式应用的性能扩展。与比特币、以太坊等货币不同,EOS是一种基于EOSIO软件项目发布的代币,也被称为区块链3.0。

索引

索引一般是指关系数据库中对某一列或多个列的值进行预排序的数据结构。在这里,索引是内存表的某一字段,我们可以根据该字段操作内存表的数据。

多索引multi_index

EOS仿造Boost库中的Multi-Index Containers,开发了C++类 eosio::multi_index(以下简称为multi_index),中文也可以叫作多索引表类。通过这个API,我们可以很简单地支持数据库表的多键排序、查找、使用上下限等功能。这个新的API使用迭代器接口,可显著提升扫表的性能。

四、编写智能合约

(一)定义程序基本结构

在链所在目录下新建一个addressbook文件夹,在addressbook文件夹中创建一个addressbook.cpp文件。

cd your_contract_path
mkdir addressbook
cd addressbook
touch addressbook.cpp

引入头文件、命名空间,

#include <eosio/eosio.hpp>

using namespace eosio;

定义合约类addressbook和其构造函数。合约类应当继承自eosio::contract。eosio::contract具有三个保护的成员,和众多公有成员函数。其中三个保护成员如下:

类型

名称

意义

eosio::name

_self

部署此账户的合约名称

eosio::name

_first_receiver

首次收到传入操作的账户

datastream< const char * >

_ds

合约的数据流

在声明派生类构造函数时,需要指明这三个成员。

class [[eosio::contract("addressbook")]] addressbook : public eosio::contract {
 public:
 addressbook(name receiver, name code, datastream<const char*> ds):
 contract(receiver, code, ds) {}
 
 private:
 
};

(二)定义数据表结构及索引

1、定义结构体

首先使用struct关键字创建一个结构体,然后用[[eosio::table]]标注这个结构体是一个合约表,这里声明了一个person结构体:

private:
struct [[eosio::table]] person {
 name key;
 std::string first_name;
 std::string last_name;
 uint64_t age;
 std::string street;
 std::string city;
 std::string state;
 };
类型说明:

name:名称类型,账号名、表名、动作名都是该类型,只能使用26个小写字母和1到5的数字,特殊符号可以使用小数点,必须以字母开头且总长不超过12。

uint64_t:无符号64位整数类型,表主键、name实质都是该类型。

这里需要注意,合约的表名与结构体的名称没有关系,因此结构体的名称不必遵循name类型的规则。

表的结构如下:

类型

名称

意义

eosio::name

key

主键 账户名

string

first_name

名字

string

last_name

姓氏

uint64_t

age

年龄

string

street

街道

string

city

城市

string

state

2、定义主键

传统数据库表通常有唯一的主键,它允许明确标识表中的特定行,并为表中的行提供标准排列顺序。

EOS合约数据库支持类似的语义,但是在multi_index容器中主键必须是唯一的无符号64位整数(即uint64_t类型)。multi_index中的对象按主键索引,以无符号64位整数主键的升序排列。

接下来我们定义一个主键函数,上文中已经说明name类型实质上是 uint64_t类型,该函数使用key.value返回一个uint64_t类型的值,并且由于key字段的含义是EOS中的账户名,因此可以保证唯一性:

uint64_t primary_key() const { return key.value;}

3、定义二级索引

multi_index容器中非主键索引可以是:

  • uint64_t

  • uint128_t

  • double

  • long double

  • eosio::checksum256

常用的是uint64_t和double类型。

使用age字段作为二级索引:

uint64_t primary_key() const { return key.value;}

4、定义多索引表

合约里的表都是通过multi_index容器来定义,我们将上面定义的person结构体传入multi_index容器并配置主键索引和二级索引:

using address_index = eosio::multi_index<"people"_n, person,
indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary>>;
>;
说明:
  • _n操作符用于定义一个name类型,上述代码将“people” 定义为name类型并作为表名;

  • person结构体被传入作为表的结构;

  • indexed_by结构用于实例化索引,第一个参数“byage”_n为索引名,第二个参数const_mem_fun为函数调用运算符,该运算符提取const值作为索引键。本例中,我们将其指向之前定义的getter函数get_secondary。

使用上述定义,现在我们有了一个名为people的表,目前addressbook.cpp的完整代码如下:

#include <eosio/eosio.hpp>

using namespace eosio;

class [[eosio::contract("addressbook")]] addressbook : public eosio::contract {
 public:
  
  // 构造函数,调用基类构造函数
 addressbook(name receiver, name code,  datastream<const char*> ds): contract(receiver, code, ds) {}
 
 private:
  // 表结构
 struct [[eosio::table]] person {
  name key;
  std::string first_name;
  std::string last_name;
  uint64_t age;
  std::string street;
  std::string city;
  std::string state;
  
  uint64_t primary_key() const { return key.value; }
  uint64_t get_secondary_1() const { return age; }
  
 };
 
 // 定义多索引表
 using address_index = eosio::multi_index<"people"_n, person, indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>>;
 
};

(三)定义数据操作方法

定义好表的结构后,我们通过[[eosio::action]]来定义对数据进行增删改的基本动作。

1、增添和修改动作

首先是提供了插入或修改数据的动作upsert,为了简化用户体验,使用单一方法负责行的插入和修改,并将其命名为 “upsert” ,即 “update” 和 “insert” 的组合。

该方法的参数应当包括所有需要存入people表的信息成员。

public:

[[eosio::action]]
void upsert(
 name user,
 std::string first_name,
 std::string last_name,
 uint64_t age,
 std::string street,
 std::string city,
 std::string state
) {}

一般来说,用户希望只有自己能对自己的记录进行更改,因此我们使用 require_auth() 来验证权限,此方法接收name类型参数,并断言执行该动作的账户等于接收的值,具有执行动作的权限:

[[eosio::action]]
void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {
  require_auth( user );
}

现在我们需要实例化已经定义配置好的表,上面我们已配置多索引表并将其声明为address_index,现在要实例化表,需要两个参数:

  • 第一个参数code,它指定此表的所有者,在这里,表的所有者为合约所部署的账户,我们使用get_first_receiver()函数传入,get_first_receiver() 函数返回该动作的第一个接受者的name类型名字。

  • 第二个参数scope,它确保表在此合约范围内的唯一性。在这里,我们使用get_first_receiver().value传入。

 address_index addresses(get_first_receiver(), get_first_receiver().value);

接下来,查询迭代器,并用变量iterator来接收:

auto iterator = addresses.find(user.value);

之后我们可以使用emplace() 函数和modify() 函数来插入或修改记录。当多索引表中未查询到该账户的记录时,使用emplace() 向表中添加;当多索引表中查询到过往记录时,使用modify() 修改原有记录。

 if( iterator == addresses.end() )
  {
    //增添
    addresses.emplace(user, [&]( auto& row ) {
      row.key = user;
      row.first_name = first_name;
      row.last_name = last_name;
      row.age = age;
      row.street = street;
      row.city = city;
      row.state = state;
    });
  }
  else {
    //修改
    addresses.modify(iterator, user, [&]( auto& row ) {
      row.key = user;
      row.first_name = first_name;
      row.last_name = last_name;
      row.age = age;
      row.street = street;
      row.city = city;
      row.state = state;
    });
  }

2、删除动作

与上文类似,定义erase动作提供删除数据的动作,查询迭代器。

[[eosio::action]]
  void erase(name user) {
    require_auth(user);

    address_index addresses(get_self(), get_first_receiver().value);

    auto iterator = addresses.find(user.value);
  
  }

这里使用check() 判断表中是否存在该记录,若不存在则给出报错,存在则使用erase删除该项。

 check(iterator != addresses.end(), "Record does not exist");
    addresses.erase(iterator);

3、保存文件

加入以上两个动作后,目前addressbook.cpp的完整代码如下:

#include <eosio/eosio.hpp>

using namespace eosio;

class [[eosio::contract("addressbook")]] addressbook : public eosio::contract {

public:

  addressbook(name receiver, name code,  datastream<const char*> ds): 
  contract(receiver, code, ds) {}

  [[eosio::action]]
  void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {
    require_auth( user );
    address_index addresses(get_first_receiver(),get_first_receiver().value);
    auto iterator = addresses.find(user.value);
    if( iterator == addresses.end() )
    {
      addresses.emplace(user, [&]( auto& row ) {
       row.key = user;
       row.first_name = first_name;
       row.last_name = last_name;
       row.age = age;
       row.street = street;
       row.city = city;
       row.state = state;
      });
    }
    else {
      addresses.modify(iterator, user, [&]( auto& row ) {
        row.key = user;
        row.first_name = first_name;
        row.last_name = last_name;
        row.age = age;
        row.street = street;
        row.city = city;
        row.state = state;
      });
    }
  }

  [[eosio::action]]
  void erase(name user) {
    require_auth(user);

    address_index addresses(get_self(), get_first_receiver().value);

    auto iterator = addresses.find(user.value);
    check(iterator != addresses.end(), "Record does not exist");
    addresses.erase(iterator);
  }

private:
  struct [[eosio::table]] person {
    name key;
    std::string first_name;
    std::string last_name;
    uint64_t age;
    std::string street;
    std::string city;
    std::string state;

    uint64_t primary_key() const { return key.value; }
    uint64_t get_secondary_1() const { return age; }

  };

  using address_index = eosio::multi_index<"people"_n, person, indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>>;

};

五、部署测试

(一)部署

1、创建addressbook账户

cleos create account eosio addressbook EOS7yK5K2mRCijPpRzStvucn53D4SybVge8uQ3hSnLaUvT4CPXzgo

注意其中:

EOS7yK5K2mRCijPpRzStvucn53D4SybVge8uQ3hSnLaUvT4CPXzgo 是存储于cleos钱包中的一个公钥,实际开发情况中需根据自己钱包中存储的公钥进行替换。

2、进入智能合约所在目录

cd your_contract_path/addressbook

3、编译

eosio-cpp-abigen-oaddressbook.wasmaddressbook.cpp
中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

4、部署合约到addressbook账户上

cd ..
cleos set contract addressbook addressbook
中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

(二)测试

1、创建两个测试账户alice和bob

cleos create account eosio alice 公钥
cleos create account eosio bob 公钥

2、插入数据

调用upsert动作插入数据

cleos push action addressbook upsert '["alice", "alice", "liddell", 9, "123 drink me way", "wonderland", "amsterdam"]' -p alice@active
cleos push action addressbook upsert '["bob", "bob", "is a guy", 49, "doesnt exist", "somewhere", "someplace"]' -p bob@active

插入成功,运行结果如下

中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

3、查询数据

查询信息一般在命令行使用cleos get table进行:

cleos get table 拥有表的账户 表所在合约名 表名

此条命令可以查询出表内的所有信息,也可以通过添加后续的约束来查询指定信息:

  • --upper XX等于或在此之前

  • --lower XX等于或在此之后

  • --key-type XXX类型

  • --index X根据第几个索引

  • --limit XX显示前几个数据

我们可以通过主键key查询表的数据

cleos get table addressbook addressbook people --lower alice

--lower alice表示查询的下界,以“alice”作为下界可以查询到两条记录:

中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

接下来通过二级索引age查询数据

cleos get table addressbook addressbook people --upper 10 \
--key-type i64 \
--index 2

--upper 10表示查询上界,即查询索引字段小于等于10的记录。--index 2表示使用二级索引查询。查询到一条记录:

中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

4、修改数据

调用upsert动作修改数据:

cleos push action addressbook upsert '["alice", "mary", "brown", 9, "123 drink me way", "wonderland", "amsterdam"]' -p alice@active

查询后可以看到记录的first_name和last_name字段已被修改:

中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

5、删除数据

调用erase动作删除数据:

cleos push action addressbook erase '["alice"]' -p alice@active

删除后查询不到alice,说明删除成功:

中移链合约常用开发介绍 (二)多索引表的使用,区块链,Powered by 金山文档

六、常见问题

更改数据表结构

需要注意的是,如果合约已经部署到合约账户上且表中已经存储了数据,那在更改表的结构如添加删除索引或字段时,则需要将表中的数据全部删除后,再将新的合约部署到合约账户上。文章来源地址https://www.toymoban.com/news/detail-740818.html

到了这里,关于中移链合约常用开发介绍 (二)多索引表的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 中移链DDC-SDK技术对接全流程(三)

    id:BSN_2021 公众号:BSN 研习社 作者:中移信息 2021年10月,BSN 提出搭建 BSN-DDC 基础网络,区块链团队自主研发中移链(CMBaaS)DDC 并与 BSN 开展合作,面向存在 DDC 业务需求的各行业客户提供接入服务,使其可便捷管理 DDC 操作,从而灵活升级产品模式,助力客户业务创新。 本文

    2024年01月17日
    浏览(27)
  • 中移链与BSN分布式云管平台集成,共同构建专属协同体系

    01 中移链与BSN分布式云管平台集成, 融入BSN生态体系 中移链OPB(OPB即开放联盟链,Open Permissioned Blockchain)与BSN基于BSN分布式云管平台,打造了中移链专属门户、中移链专属运营、中移链专属运维功能模块,在BSN分布式云管平台中构建专属于中移链的协同运作体系,为BSN分布

    2024年02月16日
    浏览(33)
  • 以太坊–智能合约开发介绍及环境搭建

    目录 1. 智能合约的概念 2. 智能合约的优点  3. 智能合约开发 3.1 支持智能合约的区块链 3.2 以太坊智能合约开发工具 3.3 以太坊智能合约开发语言 4. 智能合约开发环境搭建 4.1 准备工作 4.2 Node 与 NPM 4.3 Truffle 框架 4.4 Ganache 4.5 Metamask 4.6 VS code 与 Solidity插件 智能合约 (

    2024年02月05日
    浏览(32)
  • 嵌入式:ARM常用开发编译软件介绍

    ADS(ARM Developer Suite),是在1993年由Metrowerks公司开发是ARM处理器下最主要的开发工具。 他的前身是SDT,SDT是ARM公司几年前的开发环境软件,目前SDT早已经不再升级。ADS包括了四个模块分别是:SIMULATOR;C 编译器;实时调试器;应用函数库。ADS对汇编、C/C++、java支持的均很好,

    2024年02月06日
    浏览(38)
  • ElasticSearch7.3学习(十八)----多索引搜索

    1、multi-index 多索引搜索 多索引搜索就是一次性搜索多个index下的数据 应用场景:生产环境log索引可以按照日期分开。 2、_all metadata的原理和作用 直接可以搜索所有的field,任意一个field包含指定的就可以搜索出来。我们在进行中搜索的时候,难道是对document中的每一个

    2024年02月11日
    浏览(26)
  • 软件开发中常用数据结构介绍:C语言队列

    工作之余来写写C语言相关知识,以免忘记。今天就来聊聊 C语言实现循环队列 ,我是分享人M哥,目前从事车载控制器的软件开发及测试工作。 学习过程中如有任何疑问,可底下评论! 如果觉得文章内容在工作学习中有帮助到你,麻烦 点赞收藏评论+关注 走一波!感谢各位的

    2024年02月11日
    浏览(36)
  • 【微信小程序 | 实战开发】常用的视图容器类组件介绍和使用(1)

    个人名片: 🐼 作者简介:一名大二在校生,喜欢编程🎋 🐻‍❄️ 个人主页🥇: 小新爱学习. 🐼 个人WeChat:hmmwx53 🕊️ 系列专栏:🖼️ 零基础学Java——小白入门必备 重识C语言——复习回顾

    2024年02月02日
    浏览(35)
  • 【小程序开发必备】微信小程序常用API全介绍,附示例代码和使用场景

    ✍创作者:全栈弄潮儿 🏡 个人主页: 全栈弄潮儿的个人主页 🏙️ 个人社区,欢迎你的加入:全栈弄潮儿的个人社区 📙 专栏地址:小程序从入门到精通 【分享几个国内免费可用的ChatGPT镜像】 【10几个类ChatGPT国内AI大模型】 【用《文心一言》1分钟写一篇博客简直yyds】

    2023年04月09日
    浏览(29)
  • 游戏开发常用引擎工具介绍对比区别(UE4,Unity,Cocos,LayaAir,[egret-白鹭])

    是一套为开发实时技术而存在的引擎工具。目前广泛应用于3D建模渲染、游戏开发中。它完善的工具套件以及简易的工作流程能够使开发者快速修改或查看成果,对于代码的依赖性很低。而完整公开的源代码则能让使用者自由修改和扩展引擎功能。 是面向开发人员的 3D/2D 游戏

    2024年02月13日
    浏览(46)
  • 智能合约介绍

    介绍 智能合约是区块链实现可编程化的重要工具;在比特币时期,脚本仅限于描述交易得到内容和状态;随着智能合约的出现可以定义任何数据对象的状态擦欧总——使其成为网络上的“法律条文”或者“商业共识”。 相当于网络中的道德准则,不被第三方操控,公道在人

    2024年02月08日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包