当前位置: 首页 > news >正文

fisco bcosV3 Table智能合约开发

环境 : fisco bcos 3.11.0
webase-front : 3.1.1
console 3.8.0
table合约【3.2.0版本后的】

前言

最近在做毕设,数据的存储方式考虑使用fisco-bcos的table表存储,经过这几天的研究,发现对于fisco2fisco3版本的table表合约功能差异还是比较大的,比较起来V3的table合约功能性更丰富,更加的方便开发。

读者们要是没用过v3的链子,可以在fisco3 这里简单启动一条链子,Air版本的搭建和fisco2搭建的链子命令无多大差别【文章后面也有对应的控制台搭建命令,注意控制台2和3版本的链子不互通
然后就是webase-front要使用3.0以上的版本,链接在这里https://webasedoc.readthedocs.io/zh-cn/lab/docs/WeBASE-Install/developer.html

关于fisco3 的Table合约

不知道是不是webase-front 版本的问题,我并未在其代码仓库里找到Table.sol合约的文件,只有KVTable.sol合约。然后我去github的fisco仓库找到了fisco3的版本合约文件,还附带两个合约,都需要import进去才行
[更新一下,这些合约也可以在控制台3.8.0上的contracts/solidity文件夹上找到,注意:v3版本有两个Table合约,一个是3.2.0版本以上,一个是3.2.0以前的版本,我所有介绍的是3.2.0以上的,官方文档给的是3.2.0以前的例子]

Table.sol

// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <0.8.20;
pragma experimental ABIEncoderV2;
import "./EntryWrapper.sol";// KeyOrder指定Key的排序规则,字典序和数字序,如果指定为数字序,key只能为数字
enum KeyOrder {Lexicographic, Numerical}
struct TableInfo {KeyOrder keyOrder;string keyColumn;string[] valueColumns;
}// 更新字段,用于update
struct UpdateField {string columnName;// 考虑工具类string value;
}// 筛选条件,大于、大于等于、小于、小于等于
enum ConditionOP {GT, GE, LT, LE, EQ, NE, STARTS_WITH, ENDS_WITH, CONTAINS}
struct Condition {ConditionOP op;string field;string value;
}// 数量限制
struct Limit {uint32 offset;// count limit max is 500uint32 count;
}// 表管理合约,是静态Precompiled,有固定的合约地址
abstract contract TableManager {// 创建表,传入TableInfofunction createTable(string memory path, TableInfo memory tableInfo) public virtual returns (int32);// 创建KV表,传入key和value字段名function createKVTable(string memory tableName, string memory keyField, string memory valueField) public virtual returns (int32);// 只提供给Solidity合约调用时使用function openTable(string memory path) public view virtual returns (address);// 变更表字段// 只能新增字段,不能删除字段,新增的字段默认值为空,不能与原有字段重复function appendColumns(string memory path, string[] memory newColumns) public virtual returns (int32);// 获取表信息function descWithKeyOrder(string memory tableName) public view virtual returns (TableInfo memory);
}// 表合约,是动态Precompiled,TableManager创建时指定地址
abstract contract Table {// 按key查询entryfunction select(string memory key) public virtual view returns (Entry memory);// 按条件批量查询entry,condition为空则查询所有记录function select(Condition[] memory conditions, Limit memory limit) public virtual view returns (Entry[] memory);// 按照条件查询count数据function count(Condition[] memory conditions) public virtual view returns (uint32);// 插入数据function insert(Entry memory entry) public virtual returns (int32);// 按key更新entryfunction update(string memory key, UpdateField[] memory updateFields) public virtual returns (int32);// 按条件批量更新entry,condition为空则更新所有记录function update(Condition[] memory conditions, Limit memory limit, UpdateField[] memory updateFields) public virtual returns (int32);// 按key删除entryfunction remove(string memory key) public virtual returns (int32);// 按条件批量删除entry,condition为空则删除所有记录function remove(Condition[] memory conditions, Limit memory limit) public virtual returns (int32);
}abstract contract KVTable {function get(string memory key) public view virtual returns (bool, string memory);function set(string memory key, string memory value) public virtual returns (int32);
}

EntryWrapper.sol

这个类似于mybatisplus里面的wrapper条件构造器,用来进行附加查询条件使用,还有Entry用来做返回数据的数据结构

// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <0.8.20;
pragma experimental ABIEncoderV2;
import "./Cast.sol";// 记录,用于select和insert
struct Entry {string key;string[] fields; // 考虑2.0的Entry接口,临时Precompiled的问题,考虑加工具类接口
}contract EntryWrapper {   Cast constant cast =  Cast(address(0x100f));  Entry entry;constructor(Entry memory _entry) public {entry = _entry;}function setEntry(Entry memory _entry) public {entry = _entry;}function getEntry() public view returns(Entry memory) {return entry;}function fieldSize() public view returns (uint256) {return entry.fields.length;}function getInt(uint256 idx) public view returns (int256) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");return cast.stringToS256(entry.fields[idx]);}function getUInt(uint256 idx) public view returns (uint256) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");return cast.stringToU256(entry.fields[idx]);}function getAddress(uint256 idx) public view returns (address) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");return cast.stringToAddr(entry.fields[idx]);}function getBytes64(uint256 idx) public view returns (bytes1[64] memory) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");return bytesToBytes64(bytes(entry.fields[idx]));}function getBytes32(uint256 idx) public view returns (bytes32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");return cast.stringToBytes32(entry.fields[idx]);}function getString(uint256 idx) public view returns (string memory) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");return entry.fields[idx];}function set(uint256 idx, int256 value) public returns(int32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");entry.fields[idx] = cast.s256ToString(value);return 0;}function set(uint256 idx, uint256 value) public returns(int32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");entry.fields[idx] = cast.u256ToString(value);return 0;}function set(uint256 idx, string memory value) public returns(int32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");entry.fields[idx] = value;return 0;}function set(uint256 idx, address value) public returns(int32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");entry.fields[idx] = cast.addrToString(value);return 0;}function set(uint256 idx, bytes32 value) public returns(int32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");entry.fields[idx] = cast.bytes32ToString(value);return 0;}function set(uint256 idx, bytes1[64] memory value) public returns(int32) {require(idx >= 0 && idx < fieldSize(), "Index out of range!");entry.fields[idx] = string(bytes64ToBytes(value));return 0;}function setKey(string memory value) public {entry.key = value;}function getKey() public view returns (string memory) {return entry.key;}function bytes64ToBytes(bytes1[64] memory src) private pure returns(bytes memory) {bytes memory dst = new bytes(64);for(uint32 i = 0; i < 64; i++) {dst[i] = src[i][0];}return dst;}function bytesToBytes64(bytes memory src) private pure returns(bytes1[64] memory) {bytes1[64] memory dst;for(uint32 i = 0; i < 64; i++) {dst[i] = src[i];}return dst;}
}

Cast.sol

// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <0.8.20;
pragma experimental ABIEncoderV2;abstract contract Cast {function stringToS256(string memory) public virtual view returns (int256);function stringToS64(string memory) public virtual view returns (int64);function stringToU256(string memory) public virtual view returns (uint256);function stringToAddr(string memory) public virtual view returns (address);function stringToBytes32(string memory) public virtual view returns (bytes32);function s256ToString(int256) public virtual view returns (string memory);function s64ToString(int64) public virtual view returns (string memory);function u256ToString(uint256) public virtual view returns (string memory);function addrToString(address) public virtual view returns (string memory);function bytes32ToString(bytes32) public virtual view returns (string memory);
}

编写TableTest

这里我直接用官网的例子代码进行测试,不过官网例子与实际的table合约有出入,需要进行修改

https://fisco-bcos-doc.readthedocs.io/zh-cn/latest/docs/contract_develop/c++_contract/use_crud_precompiled.html

// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <0.8.20;
pragma experimental ABIEncoderV2;
import "./Table.sol";contract TestTable{// 创建TableManager对象,其在区块链上的固定地址是0x1002
TableManager constant tm =  TableManager(address(0x1002));
Table table;
string constant TABLE_NAME = "t_test";
constructor () public{// 创建t_test表,表的主键名为id,其他字段名为name和agestring[] memory columnNames = new string[](2);columnNames[0] = "name";columnNames[1] = "age";KeyOrder keyOrder;TableInfo memory tf = TableInfo(KeyOrder.Numerical,"id", columnNames);tm.createTable(TABLE_NAME, tf);// 获取真实的地址,存在合约中address t_address = tm.openTable(TABLE_NAME);require(t_address!=address(0x0),"");table = Table(t_address);
} function insert(string memory id,string memory name,string memory age) public returns (int32){string[] memory columns = new string[](2);columns[0] = name;columns[1] = age;Entry memory entry = Entry(id, columns);int32 result = table.insert(entry);// emit InsertResult(result);return result;
}function update(string memory id, string memory name, string memory age) public returns (int32){UpdateField[] memory updateFields = new UpdateField[](2);updateFields[0] = UpdateField("name", name);updateFields[1] = UpdateField("age", age);int32 result = table.update(id, updateFields);return result;
}function remove(string memory id) public returns(int32){int32 result = table.remove(id);return result;
}function select(string memory id) public view returns (string memory,string memory)
{Entry memory entry = table.select(id);string memory name;string memory age;if(entry.fields.length==2){name = entry.fields[0];age = entry.fields[1];}return (name,age);
}// enum ConditionOP {GT, GE, LT, LE, EQ, NE, STARTS_WITH, ENDS_WITH, CONTAINS}
// struct Condition {
//     ConditionOP op;
//     string field;
//     string value;
// }
function selectMore(string memory age)publicviewreturns (Entry[] memory entries)
{Condition[] memory conds = new Condition[](1);Condition memory eq= Condition({op: ConditionOP.EQ, field: "age",value: age});conds[0] = eq;Limit memory limit = Limit({offset: 0, count: 100});entries = table.select(conds, limit);return entries;
}}

TableInfo的问题

实际的TableInfo 结构如下

// KeyOrder指定Key的排序规则,字典序和数字序,如果指定为数字序,key只能为数字
enum KeyOrder {Lexicographic, Numerical}
struct TableInfo {KeyOrder keyOrder;string keyColumn;string[] valueColumns;
}

是需要三个参数的,而官网的例子只用两个参数,缺少的第一个参数是枚举类,意思是你的主键是string类型还是数字类型,需要标明。

Condition的问题

实际的Condition结构如下

// 筛选条件,大于、大于等于、小于、小于等于
enum ConditionOP {GT, GE, LT, LE, EQ, NE, STARTS_WITH, ENDS_WITH, CONTAINS}
struct Condition {ConditionOP op;string field;string value;
}

官网的只有两个参数,缺少的那个参数是field,也就是此条件是要用在表的哪个字段时安个。

关于主键的问题

在fisco2的table表合约开发时候,因其的设计,导致主键是可以重复的。
但在测试fisco3的table表合约开发的时候,我用重复的主键添加多个数据,发现它遵守了主键唯一的规则,有兴趣的读者可以去测试一下,特别是用TestTable的selectMore,把field改成主键字段,可以测试到返回不了多个数据

结语

这段时间会继续开发v3的table合约,在开发的时候遇到的坑和新发现会持续更新到博客上

相关文章:

fisco bcosV3 Table智能合约开发

环境 &#xff1a; fisco bcos 3.11.0 webase-front : 3.1.1 console 3.8.0 table合约【3.2.0版本后的】 前言 最近在做毕设&#xff0c;数据的存储方式考虑使用fisco-bcos的table表存储&#xff0c;经过这几天的研究&#xff0c;发现对于fisco2和 fisco3版本的table表合约功能…...

leetcode刷题记录(四十八)——128. 最长连续序列

&#xff08;一&#xff09;问题描述 128. 最长连续序列 - 力扣&#xff08;LeetCode&#xff09;128. 最长连续序列 - 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复…...

HTML中如何保留字符串的空白符和换行符号的效果

有个字符串 储值门店{{thing3.DATA}}\n储值卡号{{character_string1.DATA}}\n储值金额{{amount4.DATA}}\n当前余额{{amount5.DATA}}\n储值时间{{time2.DATA}} &#xff0c; HTML中想要保留 \n的换行效果的有下面3种方法&#xff1a; 1、style 中 设置 white-space: pre-lin…...

Linux入门——环境基础开发(上)

Linux 软件包管理器 yum 什么是软件包 在Linux操作系统中&#xff0c;安装软件的方式通常较为复杂&#xff0c;其基本流程涉及下载程序源代码并通过编译得到可执行程序。然而&#xff0c;这种方法需要开发者具备一定的编程知识和环境配置能力&#xff0c;对于许多用户而言&am…...

c++类和对象---下

文章目录 一、类的静态成员 1.1.静态成员变量&#xff1a;所有对象共享的成员变量。 1.2.静态成员函数&#xff1a;可以访问静态成员变量&#xff0c;但不能访问非静态成员变量。 二、类的继承 2.1.继承&#xff1a;子类继承父类的成员变量和成员函数。 2.2.多态&#xff1a;基…...

组件中的Props

在项目开发中,在开发某些界面时,我们可以将一些代码封装成组件来简化代码。但是,如果某些情况下组件中的某些属性不是一成不变的(比如一个头像+姓名的组件,每次使用时都需要改变其图像src和姓名字符串),我们就可以使用Props。 我们要使用Props,我们需要先在组件中声明…...

并行服务、远程SSH无法下载conda,报错404

原下载代码无效&#xff0c;报错404 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh 使用下面代码下载 wget --user-agent"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12…...

迅为RK3568开发板篇OpenHarmony配置HDF驱动控制LED-新增 topeet子系统-编写 bundle.json文件

bundle.json 文件内容如下所示&#xff1a; 下面是对各个字段的解释&#xff1a; 1. name: "ohos/demos" - 这是组件或项目的名称&#xff0c;这里表示它属于 OHOS&#xff08;OpenHarmony OS&#xff09;生态系统下的一个名为"demos"的组件。 2. descri…...

深度剖析RabbitMQ:从基础组件到管理页面详解

文章目录 一、简介二、Overview2.1 Overview->Totals2.2 Overview->Nodesbroker的属性2.3 Overview->Churn statistics2.4 Overview->Ports and contexts2.5 Overview->Export definitions2.6 Overview->Import definitions 三、Connections连接的属性 四、C…...

usb通过hdc连接鸿蒙next的常用指令

参考官方 注册报名https://www.hiascend.com/developer/activities/details/44de441ef599450596131c8cb52f7f8c/signup?channelCodeS1&recommended496144 hdc-调试命令-调测调优-系统 - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-guid…...

【落羽的落羽 C语言篇】文件操作

文章目录 一、文件的概念和分类1. 概念和分类2. 文件名3. 数据文件 三、文件操作1. 文件的打开和关闭1.1 流1.2 文件指针1.3 文件的打开和关闭 2. 文件的顺序读写3. 文件的随机读写4. 文件读取的判定5. 文件缓冲区 一、文件的概念和分类 1. 概念和分类 文件是用来保存数据的。…...

RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)

0.前言 递归&#xff01;循环神经网络Recurrent Neural Network 循环神经网络&#xff08;又称递归神经网络&#xff0c;Recurrent Neural Network&#xff0c;RNN&#xff09;。是一种用于处理序列数据的神经网络结构&#xff0c;具有记忆功能&#xff0c;能够捕捉序列中的时…...

战略与规划方法——深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具

深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具 在现代商业管理中,合理地分析和管理产品组合对于企业的成功至关重要。波士顿矩阵(BCG Matrix),又称为成长份额矩阵,是一种由波士顿咨询集团(Boston Consulting Group)在20世纪70年代提出的战略工具,用于帮助…...

【记录52】el-table-column 添加fixed属性 滚动条无法滑动

问题&#xff1a; el-table-column 添加fixed属性 滚动条无法滑动 使用element UI组件&#xff0c;用到el-table的el-table-column的fixed属性时&#xff0c;当滚动条长度小于固定列时&#xff0c;滚动条无法通过鼠标去点击滑动操作 原因 fixed是用来固定列的属性&#xff0c;其…...

晨辉面试抽签和评分管理系统之十:如何搭建自己的数据库服务器,使用本软件的网络版

晨辉面试抽签和评分管理系统&#xff08;下载地址:www.chenhuisoft.cn&#xff09;是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…...

主链和Layer2之间资产转移

主链和Layer2之间资产转移 主链和Layer2之间资产转移是实现Layer2技术的关键环节,以下是资产转移的流程、流行解决方案及原理: 资产从主链转移到Layer2 用户在主链上发起一笔交易,将资产发送到一个特定的智能合约地址,这个合约是主链与Layer2之间的桥梁。智能合约会锁定用…...

麒麟操作系统服务架构保姆级教程(十)rewrite跳转

如果你想拥有你从未拥有过的东西&#xff0c;那么你必须去做你从未做过的事情 我们访问一个网页的时候会遇到一些奇形怪状的url地址&#xff0c;想优化一下&#xff0c;看着顺眼一点&#xff0c;或者打开一个短视频软件想摸鱼刷一会视频&#xff0c;在打开界面的时候无意间按到…...

MySQL表的创建实验

创建并使用数据库mydb6_product 。 mysql> create database mydb6_product; Query OK, 1 row affected (0.01 sec)mysql> use mydb6_product; Database changed 新建employees表。 对于gender&#xff0c;有默认值意味着不为空&#xff0c;在建表时可以选择不写not nul…...

【高可用自动化体系】自动化体系

架构设计的愿景就是高可用、高性能、高扩展、高效率。为了实现架构设计四高愿景&#xff0c;需要实现自动化系统目标&#xff1a; 标准化。 流程自助化。 可视化&#xff1a;可观测系统各项指标、包括全链路跟踪。 自动化&#xff1a;ci/cd 自动化部署。 精细化&#xff1a…...

总结SpringBoot项目中读取resource目录下的文件多种方法

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…...

Java-KMP字符串匹配算法

给两个字符串s和t&#xff0c;如何很快的知道s是否包含t&#xff08;即t是否是s的子串&#xff09;。暴力的方法&#xff0c;我们依次以s每个位置为头&#xff0c;去匹配t。 public int find(String s, String t) {char[] ss s.toCharArray();char[] tt t.toCharArray();int …...

Vue3使用vue-count-to数字滚动模块报错解决方案

小伙伴们是不是遇到了vue3项目使用vue-count-to出现报错的问题 报错如下&#xff1a; TypeError: Cannot read properties of undefined (reading _c) 这个错误信息具体是说没读取到_c的属性 具体不清楚是什么原因&#xff0c;排查还得去看源码&#xff0c;所以我们来解决&a…...

【高阶数据结构】线段树加乘(维护序列)详细解释乘与加懒标记

文章目录 1.题目[AHOI2009] 维护序列 2.懒标记处理先加后乘的形式1. 先加后乘的操作 先乘后加的形式2. 先乘后加的操作**乘法操作****加法操作** 懒标记的下传 3.代码 1.题目 题目来源:https://www.luogu.com.cn/problem/P2023 [AHOI2009] 维护序列 题目背景 老师交给小可可…...

replaceState和vue的router.replace删除query参数的区别

使用history.replaceState /*** 替换当前的 history state和url* param {(searchParams:URLSearchParams)>any} cb*/ export const replaceUrlSearch (cb) > {// 获取当前 URLconst url new URL(window.location.href)// 获取 URL 的查询参数const searchParams new …...

[USACO14JAN] Ski Course Rating G

题目大意 滑雪场用一个 N ∗ M N*M N∗M 的整数矩阵表示海拔高度&#xff0c;每个整数表示一个范围在 1 0 9 10^9 109 的高度。每个格子都可以滑到相邻的格子&#xff0c;爱好者们将会在雪场种尽情享受。有些格子被指定为起点&#xff0c;每个起点都要进行评级以帮助爱好者选…...

初步认识 Neo4j 图数据库

Neo4j 是一种高性能的图数据库管理系统&#xff0c;基于图论设计&#xff0c;能够高效地存储和查询复杂的关系数据。以下是关于 Neo4j 的详细介绍&#xff1a; 核心特性 数据模型&#xff1a; Neo4j 使用图数据模型&#xff0c;将数据以节点&#xff08;Node&#xff09;、关系…...

Qt中容器 QVector、QList、QSet和QMap 性能与用途比较

表格汇总&#xff1a; 容器存储结构随机访问性能插入/删除性能主要用途QVector连续存储的动态数组 O ( 1 ) O(1) O(1)末尾&#xff1a; O ( 1 ) O(1) O(1)&#xff0c;中间&#xff1a; O ( n ) O(n) O(n)频繁随机访问&#xff0c;末尾元素的添加/删除QList优化存储&#xff0…...

ASP.NET Core - 依赖注入(四)

ASP.NET Core - 依赖注入&#xff08;四&#xff09; 4. ASP.NET Core默认服务5. 依赖注入配置变形 4. ASP.NET Core默认服务 之前讲了中间件&#xff0c;实际上一个中间件要正常进行工作&#xff0c;通常需要许多的服务配合进行&#xff0c;而中间件中的服务自然也是通过 Ioc…...

数学用语中 up to 的含义

1. 问题 在数学用语中&#xff0c;常见到“up to”这种用法&#xff0c; 但这种用法与我们常规情况下的用法不同&#xff0c;常令人困惑。 2. “等价关系”说明 已知两个数学对象 a 和 b&#xff0c;以及实数域R&#xff0c; • 当 a 和 b是通过 R 关联的&#xff0…...

Spring Boot + MyBatis-Flex 配置 ProxySQL 的完整指南

✅ Spring Boot MyBatis-Flex 配置 ProxySQL 的完整指南 下面是一个详细的教程&#xff0c;指导您如何在 Spring Boot 项目中使用 MyBatis-Flex 配置 ProxySQL 进行 读写分离 和 主从同步 的数据库访问。 &#x1f3af; 目标 在 Spring Boot 中连接 ProxySQL。使用 MyBatis-…...