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

fisco bcos CRUD编写合约的注意点

环境: ubuntu20
fisco 2.8.0
solidity 0.4.25
webase-front 1.5.2

前言

当前fiscobcos已经更新到V3版本,对于crub式的合约也支持了更多接口,有兴趣的可以尝试一下,今天写的是V2版本的fiscobcos,所以Solidity版本选择了0.4.25.

pragma solidity ^0.4.25;contract TableFactory {function openTable(string) public view returns (Table); //open tablefunction createTable(string, string, string) public returns (int256); //create table
}//select condition
contract Condition {function EQ(string, int256) public view;function EQ(string, string) public view;function EQ(string, address) public view;function NE(string, int256) public view;function NE(string, string) public view;function GT(string, int256) public view;function GE(string, int256) public view;function LT(string, int256) public view;function LE(string, int256) public view;function limit(int256) public view;function limit(int256, int256) public view;
}//one record
contract Entry {function getInt(string) public view returns (int256);function getUInt(string) public view returns (uint256);function getAddress(string) public view returns (address);function getBytes64(string) public view returns (bytes1[64]);function getBytes32(string) public view returns (bytes32);function getString(string) public view returns (string);function set(string, int256) public;function set(string, uint256) public;function set(string, string) public;function set(string, address) public;
}//record sets
contract Entries {function get(int256) public view returns (Entry);function size() public view returns (int256);
}//Table main contract
contract Table {function select(string, Condition) public view returns (Entries);function insert(string, Entry) public returns (int256);function update(string, Entry, Condition) public returns (int256);function remove(string, Condition) public returns (int256);function newEntry() public view returns (Entry);function newCondition() public view returns (Condition);
}contract KVTableFactory {function openTable(string) public view returns (KVTable);function createTable(string, string, string) public returns (int256);
}//KVTable per permiary key has only one Entry
contract KVTable {function get(string) public view returns (bool, Entry);function set(string, Entry) public returns (int256);function newEntry() public view returns (Entry);
}

编写一个管理员合约来管理

通过编写Ownable合约

pragma solidity ^0.4.25;//管理员合约
contract Ownable {address public owner;event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
//   构造器constructor () public {owner = msg.sender;}//  管理员操作修饰器modifier onlyOwner() {require(msg.sender == owner);_;}
//   管理员权限转移function transferOwnership(address newOwner) public onlyOwner {require(newOwner != address(0));emit    OwnershipTransferred(owner, newOwner);owner = newOwner;}}

然后写CRUD合约的使用可以,继承此管理员合约,在写函数方法的时候可以添加修饰器的onlyOwner来约束使用函数权限。

简单的例子

Test的crud合约

pragma solidity ^0.4.25;
import "./Table.sol";
import "./Ownable.sol";// 存储合约
contract Test is Ownable{TableFactory tf;event Result(int count);//每次影响数据的事件声明//状态 (1是正常)int256 constant status = 1;int256 constant badStatus = -1;string constant TABLE_NAME = "test1";constructor() public {tf = TableFactory(0x1001);tf.createTable(TABLE_NAME, "account", "status1,status2");}function add(address account ) public   returns(int) {int count = int(0);Table table = tf.openTable(TABLE_NAME);if(account != address(0) && !_isExist(table,account)){Entry entry = table.newEntry();entry.set("status1", status);entry.set("status2",status);count = table.insert(addressToString(account), entry);}emit Result(count);return count;}//删除function remove(address account) public onlyOwner returns(int) {int count = int(0);Table table = tf.openTable(TABLE_NAME);      if(_isExist(table,account)){Condition condition = table.newCondition();count = table.remove(addressToString(account),condition);         }emit Result(count);return count;        }// 查找function check(address account) public   view returns(int256[]){Table table = tf.openTable(TABLE_NAME);Condition condition = table.newCondition();condition.EQ("status1", status);Entries entries = table.select(addressToString(account), condition);int256[] memory status1_id_list = new int256[](uint256(entries.size()));for (int256 i = 0; i < entries.size(); ++i) {Entry entry = entries.get(i);status1_id_list[uint256(i)] = entry.getInt("status1");}return status1_id_list;}// 更新function update(address account,int256 money) public onlyOwner returns(int) {int count = int(0);Table table = tf.openTable(TABLE_NAME); if(_isExist(table,account)){Condition condition = table.newCondition();Entry entry = table.newEntry();entry.set("status1",badStatus);count = table.update(addressToString(account),entry,condition);         }emit Result(count);return count;        }function _isExist(Table _table, address  account) internal view returns(bool) {Condition condition = _table.newCondition();condition.EQ("status1", status);return _table.select(addressToString(account), condition).size() > int(0);}// 判断用户是否存在function isExist( address  account) public  view returns(bool) {Table table = tf.openTable(TABLE_NAME);return _isExist(table,account) ;}// 地址转换成Stringfunction addressToString(address _address) public pure returns (string memory _uintAsString) {uint _i = uint256(_address);if (_i == 0) {return "0";}uint j = _i;uint len;while (j != 0) {len++;j /= 10;}bytes memory bstr = new bytes(len);uint k = len - 1;while (_i != 0) {bstr[k--] = byte(uint8(48 + _i % 10));_i /= 10;}return string(bstr);}}

接下来总结一下会踩到的坑

部署表问题

在CRUD合约中,如果你部署了一个表名叫test1,那么这条fisco链子就会产生表,并且其他合约也能调用,只要正确打开Table。但是如果你写好了一个合约,在构造函数里面 有部署表的代码

  TableFactory tf;string constant TABLE_NAME = "test1";constructor() public {tf = TableFactory(0x1001);tf.createTable(TABLE_NAME, "account", "status1,status2");}

那么,你再次完善合约的代码时候,需要重新部署此合约,那么 tf.createTable(TABLE_NAME, "account", "status1,status2");此段代码就不需要了,因为CRUD合约是数据和代码是分离的,那么重新部署合约后,表的数据还会在,这就是与传统开发合约的区别所在。

表字段创建的问题

tf.createTable(TABLE_NAME, "account", "status1,status2");
这个方法一定是需要输入三个入参的,第一个是表名,第二个是主键的,第三个是其他表字段【字段之间要用英文逗号隔开】,所以如果你设计的表需要只主键这一个字段的话,那么CRUD合约就不适合你,推荐用数组或者mapping来解决业务。

主键的数据类型选择问题

可以看一下table合约对主键的定义
function createTable(string, string, string) public returns (int256); //create table
function insert(string, Entry) public returns (int256);
说明主键是要用字符串存储的,比方说我想用adddress类型的作为主键,那么就需要用转换方法,将其进行转换成字符串

  function addressToString(address _address) public pure returns (string memory _uintAsString) {uint _i = uint256(_address);if (_i == 0) {return "0";}uint j = _i;uint len;while (j != 0) {len++;j /= 10;}bytes memory bstr = new bytes(len);uint k = len - 1;while (_i != 0) {bstr[k--] = byte(uint8(48 + _i % 10));_i /= 10;}return string(bstr);}}

控制台使用查表的问题

控制台的使用sql语句可以查看系统里表的结构和数据
查看表结构

[group:1]> desc test1
[{"key_field":"account","value_field":"status1,status2"}
]

也可以查询语句,注意v2的链子必须要带主键才能查询【但是这个主键与传统的mysql的主键又有不同,因为此主键允许重复的】

[group:1]> select * from test1 where account = 261409877424322348048187072124586908683860685589
{account=261409877424322348048187072124586908683860685589, status1=1, status2=1}
1 row in set.

这是的account 是进过addressToString方法转换成的。

Entry

查询select的时候会返回Entries,里面可能有多个Entry,所以要用for循环进行调用get方法

contract Entries {function get(int256) public view returns (Entry);function size() public view returns (int256);
}

Condition

查询select还需要用到Condition这个条件类,EQ是相等,NE是不相等,GT是大于,GE是大于等于,LT是小于,LE是小于等于 ,要注意的是函数第一参数是放字段名,然后可以匹配的数据类型是int256,string和address。limit就是展示多少数据,展示哪写数据。

  function EQ(string, int256) public view;function EQ(string, string) public view;function EQ(string, address) public view;function NE(string, int256) public view;function NE(string, string) public view;function GT(string, int256) public view;function GE(string, int256) public view;function LT(string, int256) public view;function LE(string, int256) public view;function limit(int256) public view;function limit(int256, int256) public view;

http://www.mrgr.cn/news/83421.html

相关文章:

  • PostgreSQL技术内幕22:vacuum full 和 vacuum
  • Spring Cloud 集成AlloyDB
  • Xcode 正则表达式实现查找替换
  • RabbitMQ基础(简单易懂)
  • 深度学习知识点:LSTM
  • pdf提取文本,表格以及转图片:spire.pdf
  • 【应用篇】09.自主Shell命令行解释器
  • mysql中创建计算字段
  • 音视频入门基础:RTP专题(2)——使用FFmpeg命令生成RTP流
  • ollama简单上手
  • 【C语言】_使用冒泡排序模拟实现qsort函数
  • java_将数据存入elasticsearch进行高效搜索
  • Vue Router4
  • Flask----前后端不分离-登录
  • 【算法与数据结构】—— 回文问题
  • 有心力场的两体问题
  • 修改之前的代码使得利用设备树文件和Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】
  • 大模型WebUI:Gradio全解11——Chatbots:融合大模型的多模态聊天机器人(2)
  • android四大组件之一——Service
  • 探索 C++ Insights: 理解编译器背后的 C++ 实现
  • 树的模拟实现
  • python 个人学习笔记
  • RabbitMQ基础(简单易懂)
  • day06_Spark SQL
  • 【源码解析】Java NIO 包中的 ByteBuffer
  • 【Rust自学】11.7. 按测试的名称运行测试