百里登风

导航

融安链智能合约的编写

第一次接触融安区块链,其实融安链就是基于webase平台进行二次开发(简称盗版),但是里面还是相对于webase平台有很多坑

我这次编写智能合约就发现融安链在Table工具类就不支持,一直报status:16  其实就是交易回滚的错,通过查询fisco的官网,

描述这个错误是什么合约的代码逻辑,合约没有初始化等等,但是其实都不是,我是通过一点点打印日志来排查的

到最后我才发现是不能很好支持Table通用的工具类的方法调用

 

一、在融安链错误的案例,但是在天河链、webase平台运行是没有问题的

首先是Table通用工具类

 

pragma solidity ^0.4.0;

contract TableFactory {
    function openTable(string) public constant returns (Table);  // 打开表
    function createTable(string,string,string) public returns(int);  // 创建表
}

// 查询条件
contract Condition {
    //等于
    function EQ(string, int) public;
    function EQ(string, string) public;


    //大于
    function GT(string, int) public;
    //大于或等于
    function GE(string, int) public;

    //小于
    function LT(string, int) public;
    //小于或等于
    function LE(string, int) public;

    //限制返回记录条数
    function limit(int) public;
    function limit(int, int) public;
}

// 单条数据记录
contract Entry {
    function getInt(string) public constant returns(int);
    function getAddress(string) public constant returns(address);
    function getBytes64(string) public constant returns(byte[64]);
    function getBytes32(string) public constant returns(bytes32);
    function getString(string) public constant returns(string);

    function set(string, int) public;
    function set(string, string) public;
    function set(string, address) public;
}

// 数据记录集
contract Entries {
    function get(int) public constant returns(Entry);
    function size() public constant returns(int);

}

// Table主类
contract Table {
    // 查询接口
    function select(string, Condition) public constant returns(Entries);
    // 插入接口
    function insert(string, Entry) public returns(int);
    // 更新接口
    function update(string, Entry, Condition) public returns(int);
    // 删除接口
    function remove(string, Condition) public returns(int);

    function newEntry() public constant returns(Entry);
    function newCondition() public constant returns(Condition);
}

 

 

 

 

下面是我的主要核心功能的智能合约

 

pragma solidity ^0.4.2;
pragma experimental ABIEncoderV2;

import "./Table.sol";

contract GeneralContract{
    address public platform;
    TableFactory tf = TableFactory(0x1001);  // TableFactory的地址固定为0x1001
    string constant TABLE_NAME = "general_info";

    //约束条件--平台方
    modifier onlyPlatform{
        require(msg.sender==platform);
        _;
    }

    constructor() public {
        platform =msg.sender;
        create();
    }
    
    event DebugLog(string message, bool value);

    // 创建表
    function create() returns(int){
        int count = tf.createTable(TABLE_NAME, "type_tablename_id", "version,status,data");
        return count;
    }

         //查询操作
      function select(string memory type_tablename_id) public view returns(Entry){
        Table table = tf.openTable(TABLE_NAME);
        Condition condition = table.newCondition();
        condition.EQ("type_tablename_id", type_tablename_id); 
        Entries entries = table.select(type_tablename_id, condition);
        require(entries.size() == 1, "DATA_NOT_EXIST");
        return entries.get(0);
    }

     /**
     * 描述: 表名称+唯一id组合主键查询记录
     */
    function selectById(string memory type_tablename_id) 
    public view returns (string memory,string memory, string memory, string memory)
    {
        Entry entry = select(type_tablename_id);
        return (strConcat("type_tablename_id:",entry.getString("type_tablename_id")),
               strConcat("version:",entry.getString("version")),
               strConcat("status:",entry.getString("status")),
               strConcat("data:",entry.getString("data")));
    }

     /**
     * 描述: 插入记录.
     */
        function insert(string memory type_tablename_id, string memory version, int status,string memory data)  public returns (int)
    {
          emit DebugLog("Insert started", false); // 确保首个日志触发
         bool exists = checkRepeat(type_tablename_id);
         emit DebugLog("Before require", exists); // 添加日志
        //字段校验
        require(!exists,"上链数据type_tablename_id已经存在");
        Table table = tf.openTable(TABLE_NAME);
        emit DebugLog("openTable", false);
        Entry entry = table.newEntry();
         emit DebugLog("setdata", false);
        entry.set("type_tablename_id",type_tablename_id);
        entry.set("version",version);
        entry.set("status",status);
        entry.set("data",data);
        
        int count = table.insert(type_tablename_id, entry);
         emit DebugLog("Insert completed", true);
        return count;
    }


         /**
     * 描述: 修改记录
     */
    function update(string memory type_tablename_id, string memory version,int256 status,string memory data) public returns (int256)
    {
         //检查字段是否为空
        require(bytes(type_tablename_id).length>0,"type_tablename_id不能为空");
          //验证更新的数据是否存在
        require(checkRepeat(type_tablename_id),"数据不存在,信息更新失败");
        Table table = tf.openTable(TABLE_NAME);
        Entry entry = table.newEntry();
        entry.set("version", version);
        entry.set("status", status);
        entry.set("data", data);
        Condition condition = table.newCondition();
        condition.EQ("type_tablename_id", type_tablename_id);
        int256 count = table.update(type_tablename_id, entry, condition);
        return count;
    }

    /**
     * 描述: 移除记录
     */
    function remove(string memory type_tablename_id) public returns (int256) {
        Table table = tf.openTable(TABLE_NAME);
        Condition condition = table.newCondition();
        condition.EQ("type_tablename_id", type_tablename_id);
        int256 count = table.remove(type_tablename_id, condition);
        return count;
    }

      //检查记录重复
    function checkRepeat(string memory type_tablename_id)  public  returns(bool){
        Table table = tf.openTable(TABLE_NAME);
        emit DebugLog("openTable", false);
        Entry entry = table.newEntry();
        emit DebugLog("newEntry", false);
        Condition condition = table.newCondition();
        condition.EQ("type_tablename_id", type_tablename_id);
        Entries record = table.select(type_tablename_id,condition);
        emit DebugLog("Records size", record.size() > 0); // 添加日志
        return record.size()>0;
    }

    //字符串拼接
      function strConcat(string memory  _a, string memory _b) public  returns (string memory){
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        string memory ret = new string(_ba.length + _bb.length);
        bytes memory bret = bytes(ret);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++)bret[k++] = _ba[i];
        for (uint j = 0; j < _bb.length; j++) bret[k++] = _bb[j];
        return string(ret);
   }
}

 

 

在融安链运行数据上链就会报这个错误

1890bec57251131d04bfc8dac654170

 

 

二、在融安链就应该避免使用Table工具类来完成你的业务

下面是我的两个例子,其实思路都一样,只是根据我这边的业务需求,一个合约存放的是常规数据,另外一个智能合约存放的是有加密信息的交易数据

存放常规数据的智能合约

 

pragma solidity >=0.4.24 <0.6.11;

contract GenaralInfo{
    /**
     * @dev 记录结构体定义
     * @param type_tablename_id 主键标识(唯一)
     * @param version 记录版本号
     * @param status 记录状态(整型)
     * @param data 记录数据内容
     */
    struct Record {
        string type_tablename_id;
        string version;
        int256 status;
        string data;
    }

    // 主键到记录的映射(私有)
    mapping(string => Record) private general_info;
    
   

    // 事件定义
    event RecordAdded(string indexed id);       // 记录添加事件
    event RecordUpdated(string indexed id);    // 记录更新事件
    event RecordDeleted(string indexed id);    // 记录删除事件

    /**
     * @dev 检查记录是否存在
     * @param id 要检查的主键
     * @return bool 存在返回true,否则false
     */
    function isRecordExists(string memory id) public view returns (bool) {
        // 通过检查主键字段长度判断记录是否存在
        return bytes(general_info[id].type_tablename_id).length != 0;
    }

    /**
     * @dev 添加新记录
     * @param id 主键(必须唯一)
     * @param version 版本号
     * @param status 状态值
     * @param data 数据内容
     * @return bool 成功返回true
     * 要求:主键不能为空且不能重复
     */
    function insert(
        string memory id,
        string memory version,
        int256 status,
        string memory data
    ) public returns (bool) {
        // 校验1:主键不能为空
        require(bytes(id).length > 0, "主键不能为空");
        // 校验2:主键必须不存在
        require(!isRecordExists(id), "记录已存在");
        
        // 创建新记录
        general_info[id] = Record(id, version, status, data);
      
        
        // 触发添加事件
        emit RecordAdded(id);
        return true;
    }

    /**
     * @dev 更新现有记录
     * @param id 要更新的主键
     * @param version 新版本号
     * @param status 新状态值
     * @param data 新数据内容
     * @return bool 成功返回true
     * 要求:记录必须存在
     */
    function update(
        string memory id,
        string memory version,
        int256 status,
        string memory data
    ) public returns (bool) {
        // 校验:记录必须存在
        require(isRecordExists(id), "记录不存在");
        
        // 更新记录字段
        Record storage record = general_info[id];
        record.version = version;
        record.status = status;
        record.data = data;
        
        // 触发更新事件
        emit RecordUpdated(id);
        return true;
    }

    /**
     * @dev 删除记录
     * @param id 要删除的主键
     * @return bool 成功返回true
     * 要求:记录必须存在
     */
    function remove(string memory id) public returns (bool) {
        // 校验:记录必须存在
        require(isRecordExists(id), "记录不存在");
        
        // 从映射中删除记录
        delete general_info[id];
        // 触发删除事件
        emit RecordDeleted(id);
        return true;
    }

    /**
     * @dev 查询单条记录
     * @param id 要查询的主键
     * @return 返回记录的四个字段
     * 要求:记录必须存在
     */
    function selectById(string memory id) public view returns (
        string memory,
        string memory,
        string memory,
        string memory
    ) {
        // 校验:记录必须存在
        require(isRecordExists(id), "记录不存在");
        Record memory record = general_info[id];
        return (
            strConcat("type_tablename_id:",record.type_tablename_id),
            strConcat("version:",record.version),
            strConcat("status:",intToString(record.status)),
            strConcat("data:",record.data)
        );
    }
  
          //字符串拼接
      function strConcat(string memory  _a, string memory _b) public  returns (string memory){
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        string memory ret = new string(_ba.length + _bb.length);
        bytes memory bret = bytes(ret);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++)bret[k++] = _ba[i];
        for (uint j = 0; j < _bb.length; j++) bret[k++] = _bb[j];
        return string(ret);
   }
  
     //int转string 类型
   function intToString(int256 _value) internal pure returns (string memory) {
    if (_value == 0) {
        return "0";
    }
    
    bool isNegative = _value < 0;
    uint256 absValue = isNegative ? uint256(-_value) : uint256(_value);
    
    // 计算数字位数(包括负号)
    uint256 digits = 0;
    uint256 temp = absValue;
    
    while (temp != 0) {
        digits++;
        temp /= 10;
    }
    
    if (isNegative) {
        digits++; // 为负号预留位置
    }
    
    bytes memory buffer = new bytes(digits);
    uint256 index = digits - 1;
    
    // 处理负数
    if (isNegative) {
        buffer[0] = '-';
    }
    
    // 填充数字
    while (absValue != 0) {
        buffer[index] = bytes1(uint8(48 + (absValue % 10)));
        absValue /= 10;
        index--;
    }
    
    return string(buffer);
}
  
}

 

 

 

存放交易数据的智能合约

pragma solidity >=0.4.24 <0.6.11;

contract Transaction{
    /**
     * @dev 记录结构体定义
     * @param type_tablename_id 主键标识(唯一)
     * @param version 记录版本号
     * @param status 记录状态(整型)
     * @param data 记录数据内容
     */
    struct Record {
        string type_tablename_id;
        string version;
        int256 status;
        string data;
    }

    // 主键到记录的映射(私有)
    mapping(string => Record) private transaction_info;
    
   

    // 事件定义
    event RecordAdded(string indexed id);       // 记录添加事件
    event RecordUpdated(string indexed id);    // 记录更新事件
    event RecordDeleted(string indexed id);    // 记录删除事件

    /**
     * @dev 检查记录是否存在
     * @param id 要检查的主键
     * @return bool 存在返回true,否则false
     */
    function isRecordExists(string memory id) public view returns (bool) {
        // 通过检查主键字段长度判断记录是否存在
        return bytes(transaction_info[id].type_tablename_id).length != 0;
    }

    /**
     * @dev 添加新记录
     * @param id 主键(必须唯一)
     * @param version 版本号
     * @param status 状态值
     * @param data 数据内容
     * @return bool 成功返回true
     * 要求:主键不能为空且不能重复
     */
    function insert(
        string memory id,
        string memory version,
        int256 status,
        string memory data
    ) public returns (bool) {
        // 校验1:主键不能为空
        require(bytes(id).length > 0, "主键不能为空");
        // 校验2:主键必须不存在
        require(!isRecordExists(id), "记录已存在");
        
        // 创建新记录
        transaction_info[id] = Record(id, version, status, data);
      
        
        // 触发添加事件
        emit RecordAdded(id);
        return true;
    }

    /**
     * @dev 更新现有记录
     * @param id 要更新的主键
     * @param version 新版本号
     * @param status 新状态值
     * @param data 新数据内容
     * @return bool 成功返回true
     * 要求:记录必须存在
     */
    function update(
        string memory id,
        string memory version,
        int256 status,
        string memory data
    ) public returns (bool) {
        // 校验:记录必须存在
        require(isRecordExists(id), "记录不存在");
        
        // 更新记录字段
        Record storage record = transaction_info[id];
        record.version = version;
        record.status = status;
        record.data = data;
        
        // 触发更新事件
        emit RecordUpdated(id);
        return true;
    }

    /**
     * @dev 删除记录
     * @param id 要删除的主键
     * @return bool 成功返回true
     * 要求:记录必须存在
     */
    function remove(string memory id) public returns (bool) {
        // 校验:记录必须存在
        require(isRecordExists(id), "记录不存在");
        
        // 从映射中删除记录
        delete transaction_info[id];
        // 触发删除事件
        emit RecordDeleted(id);
        return true;
    }

    /**
     * @dev 查询单条记录
     * @param id 要查询的主键
     * @return 返回记录的四个字段
     * 要求:记录必须存在
     */
    function selectById(string memory id) public view returns (
        string memory,
        string memory,
        string memory,
        string memory
    ) {
        // 校验:记录必须存在
        require(isRecordExists(id), "记录不存在");
        Record memory record = transaction_info[id];
        return (
            strConcat("type_tablename_id:",record.type_tablename_id),
            strConcat("version:",record.version),
            strConcat("status:",intToString(record.status)),
            strConcat("data:",record.data)
        );
    }
    
       //字符串拼接
      function strConcat(string memory  _a, string memory _b) public  returns (string memory){
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        string memory ret = new string(_ba.length + _bb.length);
        bytes memory bret = bytes(ret);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++)bret[k++] = _ba[i];
        for (uint j = 0; j < _bb.length; j++) bret[k++] = _bb[j];
        return string(ret);
   }
   
   //int转string 类型
   function intToString(int256 _value) internal pure returns (string memory) {
    if (_value == 0) {
        return "0";
    }
    
    bool isNegative = _value < 0;
    uint256 absValue = isNegative ? uint256(-_value) : uint256(_value);
    
    // 计算数字位数(包括负号)
    uint256 digits = 0;
    uint256 temp = absValue;
    
    while (temp != 0) {
        digits++;
        temp /= 10;
    }
    
    if (isNegative) {
        digits++; // 为负号预留位置
    }
    
    bytes memory buffer = new bytes(digits);
    uint256 index = digits - 1;
    
    // 处理负数
    if (isNegative) {
        buffer[0] = '-';
    }
    
    // 填充数字
    while (absValue != 0) {
        buffer[index] = bytes1(uint8(48 + (absValue % 10)));
        absValue /= 10;
        index--;
    }
    
    return string(buffer);
}

  
}

后面两个智能合约在融安链运行是没有问题的,实测过,欢迎喜欢区块链的小伙伴一起交流学习!

 

posted on 2025-07-24 20:20  百里登峰  阅读(7)  评论(0)    收藏  举报