truffle框架快速開發合約步驟

矩陣元區塊鏈智能合約開發指南

1 適用範圍

本規範描述了矩陣元區塊鏈系統智能合約的開發約束與規範,用以指導DAPP開發者按照本規範開發基於矩陣元區塊鏈運行的應用。json

2 術語解釋

術語 術語解釋
DAPP 去中心化應用
Truffle 智能合約開發IDE

3 Quick Start

本章節描述一個簡單的智能合約開發樣例,用以描述基於矩陣元區塊鏈的智能合約開發標準與規範。給DAPP應用的開發提供參考。bash

3.1 合約功能描述

此合約開發用例用來管理學生數據,並給不一樣用戶分配不一樣的數據處理權限,實現數據
的訪問控制。數據結構

3.2 合約規劃與列表說明

3.2.1 合約存儲規劃

學生數據在合約的存儲屬性爲:app

id 學生id(對應於錢包地址)
name 學生名字
classId 學生所屬班級id
status 標記學生數據是否開除: 0 未開除 1 已開除

3.2.2 合約接口規劃

//新增學生
func addStudent(string _studentJson) public returns{};

//開除學生
func deleteStudentById0(string id) public{};

//根據Id查詢用戶
func findStudentById(string id) constant public returns{};

3.2.3 合約權限規劃

角色列表 角色具備的權限
校長 deleteStudentById, addStudent, findStudentById
班主任 addStudent, findStudentById
學生 findStudentById

3.2.4 合約文件規劃

LibStudent.sol: 學生的數據結構合約;模塊化

StudentManager.sol: 實現對學生數據的各類處理;函數

ModuleManager.sol: 實現對合約、角色、權限的模塊化處理。區塊鏈

3.3 合約代碼樣例

LibStudent.sol:

pragma solidity ^0.4.2;

import "LibInt.sol";
import "LibString.sol";
import "LibJson.sol";

library LibStudent {
    using LibJson for *;
    using LibString for *;
    using LibInt for *;
    using LibStudent for *;     //引入庫的語法

    //student對象結構體
    struct Student{
         address     id;        //學生Id  
         string      name;      //學生名稱
         string      classId;   //學生班級Id      
         uint        status;    //學生狀態 0 未開除 1 開除
    }     
   
    //將student對象轉換成json字符串
    function toJson(Student storage _self) internal returns(string _strjson){
        _strjson = "{";
        string memory strAddr = "0x";
        strAddr  = strAddr.concat(_self.id.addrToAsciiString());
        _strjson = _strjson.concat(strAddr.toKeyValue("id"), ",")
        _strjson = _strjson.concat(_self.name.toKeyValue("name"), ",");
        _strjson = _strjson.concat(_self.classId.toKeyValue("classId"), ",");
        _strjson = _strjson.concat(uint(_self.status).toKeyValue("status"), " ");
        _strjson = _strjson.concat("}");
     }

    //從student的json字符串中提取相應值
    function fromJson(Student storage _self, string _stuJson) internal returns(bool) {
         _self.clear();

        string memory strAddr = _stuJson.getStringValueByKey("id");
        strAddr = _stuJson.getStringValueByKey("id");
        _self.id= strAddr.toAddress();
        _self.name = _stuJson.jsonRead("name");
        _self.classId= _stuJson.jsonRead("classId");
        _self.status = _stuJson.jsonRead("status").toUint();
        return true;
     }

    //將student對象置空
    function clear(Student storage _self) internal {
        _self.id= address(0);
        _self.name = ""; 
        _self.classId= "";
        _self.status = 1;
    }

    //重置student對象
    function reset(Student storage _self) internal {
        clear(_self);
        _self.clear();
    }
}

StudentManager.sol:

pragma solidity ^0.4.2;

import "LibStudent.sol";
import "LibString.sol";
import "LibInt.sol";

contract StudentManager {
 
    using LibStudent for *;
    using LibString for *;
    using LibInt for *;                         //引入所需庫合約

    event Notify(uint _errno, string _info);    //定義事件處理
    
    //此mapping對象將地址映射到對象自己
    mapping(address=>LibStudent.Student)       studentMap;
    address[]                                  addrList;
    address[]                                  tempList;

    LibStudent.Student internal                student;
    string[]                                   tmpArray;

    //錯誤碼定義
    enum StudentError {
        NO_ERROR,
        BAD_PARAMETER,
        NAME_EMPTY,
        CLASS_NOT_EXISTS,
        STUDENT_NOT_EXISTS
    }

    uint errno = 0;

    //構造函數
    function StudentManager() {
    }

     //新增學生
    function addStudent(string _studentJson) public returns(uint) {
        log("insert", "StudentManager");

        if (student.fromJson(_studentJson) == false) {
            log("insert bad json", "StudentManager");
            errno = 9000 + uint(StudentError.BAD_PARAMETER);
            Notify(errno, "insert bad json");
            return errno;
        }

        if (student.name.equals("")) {
            log("student name is invalid", "StudentManager");
            errno = 9000 + uint(StudentError.NAME_EMPTY);
            Notify(errno, "student name is invalid");
           return errno;
        }

        if (student.classId.equals("")) {
            log("student classId is invalid", "StudentManager");
            errno = 9000 + uint(StudentError.CLASS_NOT_EXISTS);
            Notify(errno, "student classId is invalid");
           return errno;
        }

        student.status = uint(0);

        studentMap[student.id] = student;
        addrList.push(student.id);

        errno = uint(StudentError.NO_ERROR);

        log("add a student succcess", "StudentManager");
        Notify(errno, "insert a student succcess");
        student.reset();
        return errno;
    }

    //根據學生Id查找學生
    function findStudentById(address _id) constant public returns(string _ret) {
        _ret = "{\"ret\":0,\"data\":{"; 

        if (studentMap[_id].status != 1) {
            _ret = _ret.concat(studentMap[_id].toJson());
        } else {
            _ret = _ret.concat(""));
        }
        _ret = _ret.concat("}}");
    }

    //根據學生Id刪除學生
    function deleteStudentById(address _id) public {

        if (studentMap[_id].status == 1) {
            log("student not exists: ", _id);
            errno = 9000 + uint(StudentError.STUDENT_NOT_EXISTS);
            Notify(errno, "student not exists");
            return;
        } 
        delete tempList;
        for (uint i = 0; i < addrList.length; i++)  {
            if(_id == studentMap[addrList[i]].id) {
                continue;
            }
            else {
                tempList.push(addrList[i]);
            }
        }

        delete addrList;
        for (uint j = 0; j < tempList.length; ++j) {
            addrList.push(tempList[j]);
        }

        studentMap[_id].status = 1;
        Notify(errno, "fire student success");
    }
}

ModuleManager.sol:

pragma solidity ^0.4.2;

import "LibModule.sol";
import "LibContract.sol";
import "BaseModule.sol";

contract ModuleManager is BaseModule{
    
    //構造module對象
    LibModule.Module      tmpModule;
    
    //構造contract對象
    LibContract.Contract tmpContract;

    //構造函數,發佈入鏈即自動執行
    func ModuleManager(){
        register("ModuleManager","0.0.1.0");
        tmpModule.reset();
        string[] memory tmpArr;

        tmpModule = LibModule.Module({moduleId:"systemModule001",moduleName:"系統模塊",moduleVersion:"0.0.1.0",deleted:false,moduleEnable:1,moduleDescription:"系統模塊管理",moduleCreateTime:nowTime,moduleUpdateTime:nowTime,moduleCreator:msg.sender,contractIdList:tmpArr,roleIds:tmpArr});
        addModule(tmpModule);    //添加此模塊
        initContractData();      //添加合約
        initActionData();        //添加權限
        initRoleData();          //添加角色

    }
    
    //添加合約數據
    func initContractData() private returns(uint){
        address userAddr = rm.getContractAddress("UserManager","0.0.1.0");
        tmpContract.moduleId = sysModuleId;
        tmpContract.cctId = innerContractMapping["UserManager"];
        tmpContract.cctName = "用戶管理"; 
        tmpContract.cctVersion = "0.0.1.0"; 
        tmpContract.deleted = false;
        tmpContract.enable = 1;
        tmpContract.description = "用戶管理合約";
        tmpContract.createTime = nowTime;
        tmpContract.updateTime = nowTime;
        tmpContract.creator = msg.sender;
        tmpContract.cctAddr = userAddr;
        addContract(tmpContract.toJson());
        return 1;
    }

    //添加權限數據
    func initActionData() private returns(uint){
        string memory actionStr = "";
        
        //權限數據對象     
        jsonStr="{\"id\":\"action1000\",\"moduleId\":\"module001\",\"name\":\"addStudent\",\"resKey\":\"StudentManager\",\"opKey\":\"addStudent(string)\"}";
        addAction(jsonStr);
        jsonStr="{\"id\":\"action1001\",\"moduleId\":\"module001\",\"name\":\"findStudentById\",\"resKey\":\"StudentManager\",\"opKey\":\"findStudentById(string)\"}";
        addAction(jsonStr);
        jsonStr="{\"id\":\"action1002\",\"moduleId\":\"module001\",\"name\":\"deleteStudentById\",\"resKey\":\"StudentManager\",\"opKey\":\"deleteStudentById(string)\"}";
        addAction(jsonStr);
        return 1;
    }
    
    //添加角色數據
    func initRoleData() private returns(uint){
        string memory roleJsonStr="";
       
       //角色數據對象
        roleJsonStr="{\"id\":\"role1000\",\"name\":\"校長\",\"status\":1,\"moduleId\":\"systemModule001\",\"actionIdList\":[\"action1000\",\"action1001\",\"action1002\"]}";
        addRole(roleJsonStr);
        roleJsonStr="{\"id\":\"role1001\",\"name\":\"班主任\",\"status\":1,\"moduleId\":\"systemModule001\",\"actionIdList\":[\"action1000\",\"action1001\"]}";
        addRole(roleJsonStr);
        roleJsonStr="{\"id\":\"role1002\",\"name\":\"學生\",\"status\":1,\"moduleId\":\"systemModule001\",\"actionIdList\":[\"action1001\",]}";
        addRole(roleJsonStr);
        return 1;
    }
}

3.4 合約編譯發佈

3.4.1 前提要求

本地矩陣元區塊鏈平臺已經啓動運行。
矩陣元區塊鏈平臺搭建請參考《矩陣元區塊鏈環境安裝部署》文檔;測試

本地已搭建好Truffle環境。
Truffle編譯發佈環境搭建請參考《矩陣元區塊鏈Truffle環境搭建》文檔。ui

3.4.2 合約編譯與發佈

1)Truffle環境初始化

新建合約目錄DAPP
在新建的合約目錄DAPP下執行truffle init初始化目錄結構

修改truffle.js文件中RPC地址爲平臺地址
刪除示例合約ConvertLib.sol,MetaCoin.sol,Migrations.sol

2)上傳應用智能合約

將編寫的上述智能合約上傳到truffle init生成目錄結構下的contract中

3)合約編譯

在新建的Dapp目錄下執行命令truffle compile完成合約的編譯

4)合約發佈

修改部署配置文件:
在migrations目錄下修改migrations/1_initial_migration.js
註釋掉deployer.deploy(Migrations);

在migrations目錄下修改migrations/2_deploy_contracts.js
添加本身要發佈的合約,例:
module.exports = function(deployer) {
    deployer.deploy(StudentManager);
    deployer.deploy(ModuleManager);
};

在新建的Dapp目錄下執行命令truffle migrate完成合約的發佈。

3.4.3 合約測試

進入truffle控臺: truffle consolecode

實例化待測合約對象,如StudentManager.sol

> var stu = StudentManager.deployed();
undefined

或者:

> var stu = StudentManager.at(「0x002b4f09741a896e757f276d8f5f0c24bca870bf」);
undefined

注:該處此地址爲合約發佈時輸出的對應地址。

調用合約函數:

> stu.addStudent(‘{「id」: 「0x006d8f5f0c24bca870bf2b4f09741a896e757f27」, 「name」: 「juzix」,     「classId」: 「SuperClass」,「status」: 0}’);
「0x00aa1676c77bb7861ef115652715671880aa1677」
> stu.findStudentById(「0x006d8f5f0c24bca870bf2b4f09741a896e757f27」);
‘{「id」: 「0x006d8f5f0c24bca870bf2b4f09741a896e757f27」, 「name」: 「juzix」, 「classId」: 「SuperClass」,「status」: 0}’
> stu.deleteStudentById(「0x006d8f5f0c24bca870bf2b4f09741a896e757f27」);
「0x5652715671880aa00aa1676c77bb7861ef11ba21」

4 系統合約接口說明

系統Library庫合約以及系統合約接口說明請參考智能合約開發指南_矩陣元區塊鏈文檔

4.3 系統角色與權限說明

系統內置四種角色以及每一個角色對應的權限,分別爲:節點管理員、鏈管理員、系統管理員、權限管理員,每一個角色爲相關合約下的全部接口,四大角色全部權限以下:

角色名稱 節點管理員
角色權限 權限描述 四大合約權限以及節點信息管理權限
全部權限 UserManager, DepartmentManager, ActionManager, RoleManager, NodeInfoManager
角色名稱 鏈管理員
角色權限 權限描述 四大合約權限、鏈文件以及節點申請權限
全部權限 UserManager, DepartmentManager, ActionManager, RoleManager, NodeApplyManager, FileInfoManager, FileServerManager
角色名稱 系統管理員
角色權限 權限描述 四大合約權限以及系統配置權限
全部權限 UserManager, DepartmentManager, ActionManager, RoleManager, SystemConfig
角色名稱 權限管理員
角色權限 權限描述 機構、用戶、角色權限管理員,四大合約權限以及權限控制
全部權限 UserManager, DepartmentManager, ActionManager, RoleManager, RoleFilterManager

5 合約業務開發流程介紹

使用智能合約開發業務,需按照如下5個步驟進行:

1)完成合約基礎數據的處理;

2)實現註冊合約;

3)定義業務數據的結構,並實現對業務數據的處理;

4)根據接口文檔實現業務合約的業務邏輯;

5)模塊化管理。

流程詳情請參考智能合約開發指南_矩陣元區塊鏈文檔

相關文章
相關標籤/搜索