本規範描述了矩陣元區塊鏈系統智能合約的開發約束與規範,用以指導DAPP開發者按照本規範開發基於矩陣元區塊鏈運行的應用。json
術語 | 術語解釋 |
---|---|
DAPP | 去中心化應用 |
Truffle | 智能合約開發IDE |
本章節描述一個簡單的智能合約開發樣例,用以描述基於矩陣元區塊鏈的智能合約開發標準與規範。給DAPP應用的開發提供參考。bash
此合約開發用例用來管理學生數據,並給不一樣用戶分配不一樣的數據處理權限,實現數據
的訪問控制。數據結構
學生數據在合約的存儲屬性爲:app
id | 學生id(對應於錢包地址) |
---|---|
name | 學生名字 |
classId | 學生所屬班級id |
status | 標記學生數據是否開除: 0 未開除 1 已開除 |
//新增學生 func addStudent(string _studentJson) public returns{}; //開除學生 func deleteStudentById0(string id) public{}; //根據Id查詢用戶 func findStudentById(string id) constant public returns{};
角色列表 | 角色具備的權限 |
---|---|
校長 | deleteStudentById, addStudent, findStudentById |
班主任 | addStudent, findStudentById |
學生 | findStudentById |
LibStudent.sol: 學生的數據結構合約;模塊化
StudentManager.sol: 實現對學生數據的各類處理;函數
ModuleManager.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(); } }
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"); } }
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; } }
本地矩陣元區塊鏈平臺已經啓動運行。
矩陣元區塊鏈平臺搭建請參考《矩陣元區塊鏈環境安裝部署》文檔;測試
本地已搭建好Truffle環境。
Truffle編譯發佈環境搭建請參考《矩陣元區塊鏈Truffle環境搭建》文檔。ui
新建合約目錄DAPP 在新建的合約目錄DAPP下執行truffle init初始化目錄結構 修改truffle.js文件中RPC地址爲平臺地址 刪除示例合約ConvertLib.sol,MetaCoin.sol,Migrations.sol
將編寫的上述智能合約上傳到truffle init生成目錄結構下的contract中
在新建的Dapp目錄下執行命令truffle compile完成合約的編譯
修改部署配置文件: 在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完成合約的發佈。
進入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」
系統Library庫合約以及系統合約接口說明請參考智能合約開發指南_矩陣元區塊鏈文檔
系統內置四種角色以及每一個角色對應的權限,分別爲:節點管理員、鏈管理員、系統管理員、權限管理員,每一個角色爲相關合約下的全部接口,四大角色全部權限以下:
角色名稱 | 節點管理員 | |
---|---|---|
角色權限 | 權限描述 | 四大合約權限以及節點信息管理權限 |
全部權限 | UserManager, DepartmentManager, ActionManager, RoleManager, NodeInfoManager | |
角色名稱 | 鏈管理員 | |
角色權限 | 權限描述 | 四大合約權限、鏈文件以及節點申請權限 |
全部權限 | UserManager, DepartmentManager, ActionManager, RoleManager, NodeApplyManager, FileInfoManager, FileServerManager | |
角色名稱 | 系統管理員 | |
角色權限 | 權限描述 | 四大合約權限以及系統配置權限 |
全部權限 | UserManager, DepartmentManager, ActionManager, RoleManager, SystemConfig | |
角色名稱 | 權限管理員 | |
角色權限 | 權限描述 | 機構、用戶、角色權限管理員,四大合約權限以及權限控制 |
全部權限 | UserManager, DepartmentManager, ActionManager, RoleManager, RoleFilterManager |
使用智能合約開發業務,需按照如下5個步驟進行:
1)完成合約基礎數據的處理;
2)實現註冊合約;
3)定義業務數據的結構,並實現對業務數據的處理;
4)根據接口文檔實現業務合約的業務邏輯;
5)模塊化管理。
流程詳情請參考智能合約開發指南_矩陣元區塊鏈文檔