基于区块链的数字身份应用开发(上)
任务一:环境准备
(1)更新镜像源
apt update
(2)安装openssl、jdk、git
(3)配置JAVA_HOME环境变量
echo "export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/" >>/etc/profilesource /etc/profile
使用wget命令下载build_chain.sh区块链开发部署工具
wget -c
http://res.zhonghui.vip/blockchain/training/trace/resourse/build_ch
ain.sh
使用wget命令下载FISCO BCOS二进制程序
wget -c
http://res.zhonghui.vip/blockchain/training/trace/resourse/fisco-bcos.tar.gz
解压缩文件,使用tar命令将fisco-bcos.tar.gz压缩包解压。-x参数解压文件,-v参数显 示解压过程,-f参数指定文件
tar -xvf fisco-bcos.tar.gz
(4)搭建并启动区块链网络
bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,8545 -e /root/tools/fisco-bcosbash nodes/127.0.0.1/start_all.sh
(5)安装并启动WeBASE-Front服务
使用wget命令下载WeBASE-Front程序
wget -c http://res.zhonghui.vip/blockchain/training/trace/resourse/webasefront.zip
使用unzip命令解压缩webase-front.zip文件
unzip webase-front.zip
将sdk密钥文件复制到webase-front/conf/文件夹
cp -r nodes/127.0.0.1/sdk/* webase-front/conf/
启动WeBASE-Front程序
cd webase-front
bash start.sh
(6)智能合约开发
创建项目文件
编写数字身份(DID.sol)合约
// SPDX-License-Identifier: SimPL-2.0
pragma experimental ABIEncoderV2;
pragma solidity ^0.6.10;
contract DID{
address private issuer;
address private owner;
string private did;
bool private status;
event ClaimChange(int256 retCode, address addr);
struct claim {
address claimAddr;
string claimType;
uint256 timestamp;
}
int256 private RET_SUCCESS = 0;
int256 private RET_EXISTED = -1;
claim[] private claims;
modifier onlyOwner(address identity, address actor) {
require(identity == actor, "Auth:Permissions error!");
_;
}
constructor (address _owner) public {
owner = _owner;
issuer = msg.sender;
did = DIDWrapper(addressToString(_owner));
status = true;
}
function addressToString(address addr) private pure
returns(string memory) {
bytes20 value = bytes20(uint160(addr));
bytes memory strBytes = new bytes(42);
strBytes[0] = '0';
strBytes[1] = 'x';
for(uint i = 0; i < 20; i++){
uint8 byteValue = uint8(value[i]);
strBytes[2 + (i<<1)] = encode(byteValue >> 4);
strBytes[3 + (i<<1)] = encode(byteValue & 0x0f);
}
}
return string(strBytes);
}
function encode(uint8 num) private pure returns(byte) {
if(num >= 0 && num <= 9){
return byte(num + 48);
}
return byte(num + 87);
}
function DIDWrapper(string memory addr) private pure
returns(string memory) {
string memory new_str = string(abi.encodePacked("did", ":",
"fisco", ":", addr));
return new_str;
}
function getDIDInfo() public view returns(address, address,
string memory, bool) {
return (issuer, owner, did, status);
}
function getDID() public view returns(string memory) {
return did;
}
function setStatus(bool _status) public onlyOwner(issuer,
msg.sender) {
status = _status;
}
function addClaim(address _claimAddr, string memory _claimType)
public onlyOwner(owner, msg.sender) returns (int256){
uint length = claims.length;
for (uint index = 0; index < length; index++){
claim storage instance = claims[index];
if(instance.claimAddr == _claimAddr){
emit ClaimChange(RET_EXISTED, _claimAddr);
return RET_EXISTED;
}
}
claims.push(claim({
claimAddr: _claimAddr,
claimType: _claimType,
timestamp: now
}));
emit ClaimChange(RET_SUCCESS, _claimAddr);
return RET_SUCCESS;
}
function queryClaims() public view returns(address[] memory,
string[] memory, uint256[] memory){
uint length = claims.length;
address[] memory claimAddrs = new address[](length);
string[] memory claimTypes = new string[](length);
uint256[] memory timestamps = new uint256[](length);
for (uint index = 0; index < length; index++) {
claim storage instance = claims[index];
claimAddrs[index] = instance.claimAddr;
claimTypes[index] = instance.claimType;
timestamps[index] = instance.timestamp;
}
return (claimAddrs, claimTypes, timestamps);
}
}
编写身份管理中心(DIDHub.sol)合约
// SPDX-License-Identifier: SimPL-2.0
pragma experimental ABIEncoderV2;
pragma solidity ^0.6.10;
import "Table.sol";
import "DID.sol";
contract DIDHub {
address private owner;
uint256 private VERSION = 1;
event createdDIDEvent(string did);
event setRevokedEvent(bool ok, string did);
modifier onlyOwner {
require(owner == msg.sender, "Auth:only owner is
authorized.");
_;
}
constructor() public {
owner = msg.sender;
createTable();
}
function createTable() private {
KVTableFactory kvtf = KVTableFactory(0x1010);
kvtf.createTable("Document", "did", "context, version,
createTime, publicKey");
}
function openTable() private view returns(KVTable){
KVTableFactory kvtf = KVTableFactory(0x1010);
KVTable kvTable = kvtf.openTable("Document");
return kvTable;
}
function createDID(address _addr, string memory _publicKey )
public onlyOwner returns(string memory){
DID DIDContract = new DID(_addr);
KVTable kvTable = openTable();
Entry document = kvTable.newEntry();
document.set("did", DIDContract.getDID());
document.set("context", address(DIDContract));
document.set("version", VERSION);
document.set("createTime", now);
document.set("publicKey", _publicKey);
kvTable.set(DIDContract.getDID(), document);
emit createdDIDEvent(DIDContract.getDID());
return (DIDContract.getDID());
}
struct Document {
string did;
address context;
uint version;
uint createTime;
string publicKey;
}
function getDocument(string memory _did) public view
returns(Document memory){
KVTable kvTable = openTable();
bool ok = false;
Entry entry;
Document memory document;
(ok, entry) = kvTable.get(_did);
if(ok){
document.did = entry.getString("did");
document.context = entry.getAddress("context");
document.version = entry.getUInt("version");
document.createTime = entry.getUInt("createTime");
document.publicKey = entry.getString("publicKey");
}
return (document);
}
function setRevoked(string memory _did, bool _status) public
onlyOwner returns(bool) {
KVTable kvTable = openTable();
bool ok = false;
Entry entry;
address context;
// 调用KVTable的get方法,返回entry实例对象
(ok, entry) = kvTable.get(_did);
if(ok){
context = entry.getAddress("context");
DID DIDContract = DID(context);
DIDContract.setStatus(_status);
}
emit setRevokedEvent(ok, _did);
return ok;
}
}
DIDHub 合约利用 CRUD 合约接口对 DID 和 DID文档进行存储映射,所以需要导入” Table.sol“ 合约,在终端输入如下命令,回到工作目录并下载 ”Table.sol“ 合约文件
cd .. && wget
http://res.zhonghui.vip/blockchain/DID/resource/Table.sol
编写工作声明(WorkClaim.sol )合约编码
// SPDX-License-Identifier: SimPL-2.0
pragma experimental ABIEncoderV2;
pragma solidity ^0.6.10;
contract WorkClaim{
struct Claim {
address issuer;
string issuerID;
uint256 issuerTime;
string userName;
string userID;
string companyName;
string post;
string employmentDate;
string leaveDate;
}
Claim private claim;
string private signature;
constructor(string memory _issuerId,
string memory _name, string memory _userId,
string memory _companyName, string memory _post,
string memory _employmentDate, string memory _leaveDate)
public {
claim.issuer = msg.sender;
claim.issuerID = _issuerId;
claim.issuerTime = now;
claim.userName = _name;
claim.userID = _userId;
claim.companyName = _companyName;
claim.post = _post;
claim.employmentDate = _employmentDate;
claim.leaveDate = _leaveDate;
}
function setSign(string memory _signature) public {
require(claim.issuer == msg.sender);
signature = _signature;
}
function getSign() public view returns(string memory){
return signature;
}
function getClaimInfo() public view returns(Claim memory){
return claim;
}
}
导出合约文件
在浏览器左下角可以观察到导出的“contracts.zip”压缩包,压缩包保存在 “/root/Downloads”文件夹下