智能合约开发与测试
任务一:智能合约设计
(1)编写新能源智能合约功能需求文档。
区块链新能源管理智能合约功能需求包括资产与能源绑定、用户管理、能源交易、智能结算等,确保安全性、隐私保护和可扩展性,提高能源利用效率,促进能源流转,实现自动化交易与透明管理。 |
---|
(2)完成区块链新能源管理智能合约的设计。
-
设计区块链新能源管理智能合约接口,画出区块链新能源管理智能合约的角色UML用例图;
-
以图文结合的方式描述智能合约各参与实体间的关系。
任务二:智能合约开发
(1)太阳能板管理接口编码
-
根据文档要求,编写太阳能板新增接口功能,必须将新增太阳能板数据存入指定表中,在存储完成后需触发后事件并返回存储与否的标识;
-
根据文档要求,编写太阳能板修改接口,必须通过指定表修改完成数据更新,在完成更新后需触发事件并返回更新与否的标识。
编写SolarPanelsStorage.sol
/** * 太阳能板详情存储器,记录太阳能板的详细信息 */ pragma solidity ^0.4.25; pragma experimental ABIEncoderV2; import "./Table.sol"; import "./LibString.sol"; import "./Ownable.sol"; import "./MapStorage.sol"; contract SolarPanelsStorage is Ownable { using LibString for string; MapStorage private mapStorage; event InsertResult(int256); event UpdateResult(int256); TableFactory tf; string constant TABLE_NAME = "sp_goods"; string constant TABLE_NAME2 = "_interface"; string constant TABLE_NAME3 = "spu_order"; /** * 创建太能能电池板实体 * +---------------------------+----------------+-----------------------------------------+ * | Field | Type | Desc | * +---------------------------+----------------+-----------------------------------------+ * | num_id | string | 编号 * | sp_name | string | 太阳能板名称 * | sp_actual_Power | string | 实际功率(单位:W) * | sp_rated_Power | string | 额定功率(单位:W) * | sp_input_Time | string | 生效时间(单位:h) * | sp_position | string | 投放位置 * | sp_price | string | 单价 (单位:元) * | Owner_ship | string | 所属权(address) * +---------------------------+----------------+-----------------------------------------+ */ constructor() public { tf = TableFactory(0x1001); tf.createTable(TABLE_NAME, "num_id", "sp_name,sp_actual_Power,sp_rated_Power,sp_input_Time,sp_position,sp_price,Owner_ship"); tf.createTable(TABLE_NAME2, "Owner_ship", "num_id,sp_name,sp_actual_Power,sp_rated_Power,sp_input_Time,sp_position,sp_price"); tf.createTable(TABLE_NAME3, "Owner_ship", "data,from,to,num_id"); mapStorage = new MapStorage(); } //TABLE_NAME(表1) /** * "85414020.00,太阳能电池,150W,205W,20h,China,5000RMB,test" * 插入数据 */ function insert(string memory _numid, string memory name, string memory actual_Power,string memory rated_Power,string memory input_Time, string memory position,string memory price,string Ownership) public onlyOwner returns(int) { // Goods memory _goods = convertGoods(_goodsStr); Table table = tf.openTable(TABLE_NAME); Entry entry = table.newEntry(); // convertEntry(_goods, entry); entry.set("num_id",_numid); entry.set("sp_name",name); entry.set("sp_actual_Power",actual_Power); entry.set("sp_rated_Power",rated_Power); entry.set("sp_input_Time",input_Time); entry.set("sp_position",position); entry.set("sp_price",price); entry.set("Owner_ship",Ownership); int256 count = table.insert(_numid, entry); emit InsertResult(count); return count; } /** * "1,太阳能电池,150W,205W,20h,China,1000RMB,test" * 更新数据 */ function update(string memory _numid, string memory _goodsStr) public onlyOwner returns(int256) { Goods memory _goods = convertGoods(_goodsStr); Table table = tf.openTable(TABLE_NAME); require(_isnumidExist(table, _goods.numid), "update: current numid not exist"); Entry entry = table.newEntry(); convertEntry(_goods, entry); Condition condition = table.newCondition(); int256 count = table.update(_numid, entry, condition); emit UpdateResult(count); return count; } /** * 85414020.00 * test3 * 更改所属权 */ function transfer(string memory _numid, string memory Ownership) public returns(int256) { Table table = tf.openTable(TABLE_NAME); // require(_isnumidExist(table, _numid), "update: current numid not exist"); Entry entry = table.newEntry(); entry.set("sp_price", "已出售"); entry.set("Owner_ship", Ownership); Condition condition = table.newCondition(); int256 count = table.update(_numid, entry, condition); emit UpdateResult(count); return count; } /** * 85414020.00 * test3 * 更改单价 */ function saller(string memory _numid, string memory _price) public returns(int256) { int code = 0; Table table = tf.openTable(TABLE_NAME); require(_isnumidExist(table, _numid), "0"); Entry entry = table.newEntry(); entry.set("sp_price", _price); Condition condition = table.newCondition(); int256 count = table.update(_numid, entry, condition); if(count != 1) { // 失败? 无权限或者其他错误? code = 0; return code; } emit UpdateResult(count); return count; } /** * 通过numid查询数据 */ function getDetail(string memory _num_id) public view returns(string[] memory){ Table table = tf.openTable(TABLE_NAME); Condition condition = table.newCondition(); Entries entries = table.select(_num_id, condition); string[] memory value_list = new string[](uint256(entries.size())); for (int256 i = 0; i < entries.size(); ++i) { Entry entry = entries.get(i); value_list[uint256(i)] = _returnData(entry); } return value_list; } function convertGoods(string memory _str) private returns(Goods){ string[] memory ss = _str.split(","); return Goods(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7]); } function convertEntry(Goods memory _goods, Entry entry) private { entry.set("num_id",_goods.numid); entry.set("sp_name",_goods.name); entry.set("sp_actual_Power",_goods.actual_Power); entry.set("sp_rated_Power",_goods.rated_Power); entry.set("sp_input_Time",_goods.input_Time); entry.set("sp_position",_goods.position); entry.set("sp_price",_goods.price); entry.set("Owner_ship",_goods.Ownership); } function _isnumidExist(Table _table, string memory _id) internal view returns(bool) { Condition condition = _table.newCondition(); return _table.select(_id, condition).size() != int(0); } //拼接成json数据 function _returnData(Entry _entry) internal view returns(string){ string memory _json = "{"; _json = _json.concat("'numid':'"); _json = _json.concat(_entry.getString("num_id")); _json = _json.concat("',"); _json = _json.concat("'name':'"); _json = _json.concat(_entry.getString("sp_name")); _json = _json.concat("',"); _json = _json.concat("'actual_Power':'"); _json = _json.concat(_entry.getString("sp_actual_Power")); _json = _json.concat("',"); _json = _json.concat("'rated_Power':'"); _json = _json.concat(_entry.getString("sp_rated_Power")); _json = _json.concat("',"); _json = _json.concat("'input_Time':'"); _json = _json.concat(_entry.getString("sp_input_Time")); _json = _json.concat("',"); _json = _json.concat("'position':'"); _json = _json.concat(_entry.getString("sp_position")); _json = _json.concat("',"); _json = _json.concat("'price':'"); _json = _json.concat(_entry.getString("sp_price")); _json = _json.concat("',"); _json = _json.concat("'Ownership':'"); _json = _json.concat(_entry.getString("Owner_ship")); _json = _json.concat("'"); _json = _json.concat("}"); return _json; } struct Goods { string numid; //编号 string name; //太阳能板名称 string actual_Power; //实际功率(单位:W) string rated_Power; //额定功率(单位:W) string input_Time; //生效时间(单位:h) string position; //投放位置 string price; //单价 (单位:元) string Ownership; //所属权(address) } /** * 插入数据,已有数据不添加 */ function insert2(string memory Owner_ship, string memory numid, string memory name, string memory actual_Power,string memory rated_Power,string memory input_Time, string memory position,string memory price) public onlyOwner returns(int) { // Assert memory _assert = convertAssert2(_value); Table table = tf.openTable(TABLE_NAME2); Entry entry = table.newEntry(); // convertEntry2(_assert, entry); entry.set("num_id",numid); entry.set("sp_name",name); entry.set("sp_actual_Power",actual_Power); entry.set("sp_rated_Power",rated_Power); entry.set("sp_input_Time",input_Time); entry.set("sp_position",position); entry.set("sp_price",price); entry.set("Owner_ship",Owner_ship); int count = table.insert(Owner_ship, entry); return count; } /** * 通过key获取value,可以存在多个value */ function select2(string memory _key) public view returns(string[] memory){ Table table = tf.openTable(TABLE_NAME2); Condition condition = table.newCondition(); Entries entries = table.select(_key, condition); string[] memory value_list = new string[](uint256(entries.size())); for (int256 i = 0; i < entries.size(); ++i) { Entry entry = entries.get(i); value_list[uint256(i)] = _returnData2(entry); } return value_list; } // function saller2(string memory Owner_ship, string memory _price) public returns(int256) { // int code = 0; // Table table = tf.openTable(TABLE_NAME2); // Entry entry = table.newEntry(); // entry.set("sp_price", _price); // Condition condition = table.newCondition(); // int256 count = table.update(Owner_ship, entry, condition); // if(count != 1) { // // 失败? 无权限或者其他错误? // code = 0; // return code; // } // emit UpdateResult(count); // return count; // } function convertAssert2(string memory _str) private returns(Assert){ string[] memory ss = _str.split(","); return Assert(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7]); } function convertEntry2(Assert memory _assert, Entry entry) private { entry.set("num_id",_assert.numid); entry.set("sp_name",_assert.name); entry.set("sp_actual_Power",_assert.actual_Power); entry.set("sp_rated_Power",_assert.rated_Power); entry.set("sp_input_Time",_assert.input_Time); entry.set("sp_position",_assert.position); entry.set("sp_price",_assert.price); entry.set("Owner_ship",_assert.Ownership); } //拼接成json数据 function _returnData2(Entry _entry) internal view returns(string){ string memory _json = "{"; _json = _json.concat("numid:'"); _json = _json.concat(_entry.getString("num_id")); _json = _json.concat("',"); _json = _json.concat("name:'"); _json = _json.concat(_entry.getString("sp_name")); _json = _json.concat("',"); _json = _json.concat("actual_Power:'"); _json = _json.concat(_entry.getString("sp_actual_Power")); _json = _json.concat("',"); _json = _json.concat("rated_Power:'"); _json = _json.concat(_entry.getString("sp_rated_Power")); _json = _json.concat("',"); _json = _json.concat("input_Time:'"); _json = _json.concat(_entry.getString("sp_input_Time")); _json = _json.concat("',"); _json = _json.concat("position:'"); _json = _json.concat(_entry.getString("sp_position")); _json = _json.concat("',"); _json = _json.concat("price:'"); _json = _json.concat(_entry.getString("sp_price")); _json = _json.concat("',"); _json = _json.concat("Ownership:'"); _json = _json.concat(_entry.getString("Owner_ship")); _json = _json.concat("'"); _json = _json.concat("}"); return _json; } struct Assert { string numid; //编号 string name; //太阳能板名称 string actual_Power; //实际功率(单位:W) string rated_Power; //额定功率(单位:W) string input_Time; //生效时间(单位:h) string position; //投放位置 string price; //单价 (单位:元) string Ownership; //所属权(address) } function insertorder(string memory Owner_ship,string memory _from,string memory _to,string memory _numid) public returns(int) { Table table = tf.openTable(TABLE_NAME3); Entry entry = table.newEntry(); entry.set("from", _from); entry.set("to",_to); entry.set("num_id",_numid); int count = table.insert(Owner_ship, entry); return count; } function selectorder(string memory Owner_ship) public view returns(string[] memory){ Table table = tf.openTable(TABLE_NAME3); Condition condition = table.newCondition(); Entries entries = table.select(Owner_ship, condition); string[] memory value_list = new string[](uint256(entries.size())); for (int256 i = 0; i < entries.size(); ++i) { Entry entry = entries.get(i); value_list[uint256(i)] = _returnData3(entry); } return value_list; } function uint2str(uint i) internal returns (string c) { if (i == 0) return "0"; uint j = i; uint length; while (j != 0){ length++; j /= 10; } bytes memory bstr = new bytes(length); uint k = length - 1; while (i != 0){ bstr[k--] = byte(48 + i % 10); i /= 10; } c = string(bstr); } function getDate() public view returns(string) { uint time = uint(now); return uint2str(time); } function _returnData3(Entry _entry) internal view returns(string){ string memory _json = "{"; _json = _json.concat("data:'"); _json = _json.concat(getDate()); _json = _json.concat("',"); _json = _json.concat("from:'"); _json = _json.concat(_entry.getString("from")); _json = _json.concat("',"); _json = _json.concat("to:'"); _json = _json.concat(_entry.getString("to")); _json = _json.concat("',"); _json = _json.concat("num_id:'"); _json = _json.concat(_entry.getString("num_id")); _json = _json.concat("'"); _json = _json.concat("}"); return _json; } // function getDetail(string memory _num_id) public view returns(string memory _json){ // Entry entry = select(_num_id); // _json = _returnData(entry); // } // /** // * 通过numid获取实体 // */ // function select(string memory _numid) private view returns(Entry _entry){ // Table table = tf.openTable(TABLE_NAME); // require(_isnumidExist(table, _numid), "select: current numid not exist"); // Condition condition = table.newCondition(); // _entry = table.select(_numid, condition).get(int(0)); // } // function select2( string memory id) public view returns(string[] memory){ // Table table =tf.openTable(TABLE_NAME); // // require(_isnumidExist(table, _numid), "select: current numid not exist"); // Condition condition = table.newCondition(); // // condition.limit(2); // // condition.EQ("Owner_ship", _Owner_ship); // Entries entries = table.select(id, condition); // string[] memory list = new string[](uint256(entries.size())); // for(int i = 0; i < entries.size(); ++i){ // Entry entry = entries.get(i); // list[uint256(i)] = entry.getString("Owner_ship"); // } // return list; // // _entry = table.select(_numid, condition).get(int(7)); // } // function SelectOwnership(string memory _Owner_ship) public view returns(string, string){ // Table table = tf.openTable(TABLE_NAME); // Condition condition = table.newCondition(); // Entries entries = table.select(_Owner_ship, condition); // for(int i = 0; i < entries.size(); ++i){ // return select2(i); // } // } // function select3(string memory _numid) public view returns (string[] memory,string[] memory,string[] memory, // string[] memory,string[] memory,string[] memory,string[] memory,string[] memory) // { // Table table = tf.openTable(TABLE_NAME); // Condition condition = table.newCondition(); // Entries entries = table.select(_numid, condition); // string[] memory a = new string[](uint256(entries.size())); // string[] memory b = new string[](uint256(entries.size())); // string[] memory c = new string[](uint256(entries.size())); // string[] memory d = new string[](uint256(entries.size())); // string[] memory e = new string[](uint256(entries.size())); // string[] memory f = new string[](uint256(entries.size())); // string[] memory g = new string[](uint256(entries.size())); // string[] memory h = new string[](uint256(entries.size())); // for (int256 i = 0; i < entries.size(); ++i) { // Entry entry = entries.get(i); // a[uint256(i)] = entry.getString("numid"); // b[uint256(i)] = entry.getString("name"); // c[uint256(i)] = entry.getString("actual_Power"); // d[uint256(i)] = entry.getString("rated_Power"); // e[uint256(i)] = entry.getString("input_Time"); // f[uint256(i)] = entry.getString("position"); // g[uint256(i)] = entry.getString("price"); // h[uint256(i)] = entry.getString("Ownership"); // } // return (a, b, c, d, e, f, g, h); // } }
(2)能源管理接口编码
-
根据文档要求,编写能源新增接口功能,必须将新增能源数据存入指定表中,在存储完成后需触发后事件并返回存储与否的标识;
-
根据文档要求,编写能源修改接口,必须通过指定表修改完成数据更新,在完成更新后需触发事件并返回更新与否的标识。
/** * 电力能源详情存储器,记录电力能源详细信息 */ pragma solidity ^0.4.25; pragma experimental ABIEncoderV2; import "./Table.sol"; import "./LibString.sol"; import "./Ownable.sol"; contract EnergyStorage is Ownable { using LibString for string; event Result(int count); TableFactory tf; string constant TABLE_NAME = "E_energy"; string constant TABLE_NAME2 = "E_order"; constructor() public { tf = TableFactory(0x1001); tf.createTable(TABLE_NAME, "num_id", "energy"); tf.createTable(TABLE_NAME2, "UAddress", "id,from,to,total,price"); } /** * "" * 插入数据 */ function insert(string memory _numid) public returns(int) { int count = int(0); Table table = tf.openTable(TABLE_NAME); if(!_numid.empty()){ Entry entry = table.newEntry(); entry.set("energy", int(0)); count = table.insert(_numid, entry); } emit Result(count); return count; } function insert2(string memory _UAddress, string memory order) public returns(int) { int count = int(0); Order memory _order = convertGoods(order); Table table = tf.openTable(TABLE_NAME2); if(!_UAddress.empty()){ Entry entry = table.newEntry(); convertEntry(_order, entry); count = table.insert(_UAddress, entry); } return count; } function update(string memory _numid) public returns(int) { int count = int(0); int produce_random = rand(); Table table = tf.openTable(TABLE_NAME); if(!_numid.empty()){ Entry entry = table.newEntry(); entry.set("energy", produce_random); count = table.insert(_numid, entry); } emit Result(count); return count; } /** * 通过key获取value,可以存在多个value */ function select(string memory _numid) public view returns(int[] memory){ Table table = tf.openTable(TABLE_NAME); Condition condition = table.newCondition(); Entries entries = table.select(_numid, condition); int[] memory value_list = new int[](uint256(entries.size())); for (int256 i = 0; i < entries.size(); ++i) { Entry entry = entries.get(i); value_list[uint256(i)] = entry.getInt("energy"); } return value_list; } function getOrder(string memory _id) public view returns(string[] memory){ Table table = tf.openTable(TABLE_NAME2); Condition condition = table.newCondition(); Entries entries = table.select(_id, condition); string[] memory value_list = new string[](uint256(entries.size())); for (int256 i = 0; i < entries.size(); ++i) { Entry entry = entries.get(i); value_list[uint256(i)] = _returnData(entry); } return value_list; } //能量总和 function getEnergy(string memory _numid) public view returns(uint){ int[] memory value_list = select(_numid); uint total = 0; for (uint256 i = 0; i < value_list.length; i++) { // Arr[i] = uint(value_list[uint256(i)]); total += uint(value_list[uint256(i)]); } return total; } function remove(string memory _numid, string memory _energy) public returns(int) { int count = int(0); Table table = tf.openTable(TABLE_NAME); Condition condition = table.newCondition(); condition.EQ("energy",_energy); count = table.remove(_numid,condition); emit Result(count); return count; } //产生随机数 function rand() private view returns(int) { int rand = int(keccak256(abi.encodePacked(block.difficulty, now))) % 100; if(rand < 70 && rand > 50){rand += 60;} if(rand < 50 && rand > 40){rand += 70;} if(rand < 40 && rand > 30){rand += 80;} if(rand < 30 && rand > 20){rand += 90;} if(rand < 20){rand += 100;} if(rand <= 0){rand += 110;} return rand; } //拼接成json数据 function _returnData(Entry _entry) internal view returns(string){ string memory _json = "{"; _json = _json.concat("'UAddress':'"); _json = _json.concat(_entry.getString("UAddress")); _json = _json.concat("',"); _json = _json.concat("'id':'"); _json = _json.concat(_entry.getString("id")); _json = _json.concat("',"); _json = _json.concat("'from':'"); _json = _json.concat(_entry.getString("from")); _json = _json.concat("',"); _json = _json.concat("'to':'"); _json = _json.concat(_entry.getString("to")); _json = _json.concat("',"); _json = _json.concat("'total':'"); _json = _json.concat(_entry.getString("total")); _json = _json.concat("',"); _json = _json.concat("'price':'"); _json = _json.concat(_entry.getString("price")); _json = _json.concat("'"); _json = _json.concat("}"); return _json; } function convertGoods(string memory _str) private returns(Order){ string[] memory ss = _str.split(","); return Order(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5]); } function convertEntry(Order memory _order, Entry entry) private { entry.set("UAddress",_order._UAddress); entry.set("id",_order._id); entry.set("from",_order._from); entry.set("to",_order._to); entry.set("total",_order._total); entry.set("price",_order._price); } struct Order{ string _UAddress; string _id; string _from; string _to; string _total; string _price; } // struct Energy { // string Ownership; // string energy_loss; //能量损耗 // string energy_produce; //剩余能量 // string today_produce; //今日发电 // string tody_loss;//今日消耗 // string yesterday_produce;//昨日发电 // string yesterday_loss;//昨日消耗 // string week_produce;//本周发电 // string week_loss;//本周消耗 // string month_produce;//本月发电 // string month_loss;//本月消耗 // } /** * 创建质押物品表 * +---------------------------+----------------+-----------------------------------------+ * | Field | Type | Desc | * +---------------------------+----------------+-----------------------------------------+ * | num_id string * | energy_loss; string | energy_produce; string | today_produce; string | tody_loss; string | yesterday_produce; string | yesterday_loss; string | week_produce; string | week_loss; string | month_produce; string | month_loss; string * +---------------------------+----------------+-----------------------------------------+ */ }
(3)合约部署和调用
-
解决代码错误和警告,正确编译并部署合约,成功获取部署的合约地址和ABI;
-
调用太阳能板查询合约接口,完整验证业务流程;
查询新增太阳能板数据
查询新增太阳能板数据
-
调用能源查询合约接口,完整验证业务流程。
使用energy_insert接口,新增能源。
使用太阳能板编号查询新增能源。(get_numid_Energy)
任务三:智能合约测试
-
调用太阳能板查询合约接口,完整验证业务流程;
-
调用能源查询合约接口,完整验证业务流程。