??運(yùn)行環(huán)境:ubuntu18.04 ?? docker基礎(chǔ)環(huán)境
環(huán)境變量設(shè)置
export FABRIC_PATH=/路徑/fabric-samples
export FABRIC_CFG_PATH=${FABRIC_PATH}/config/
export MSP_PATH=${FABRIC_PATH}/test-network/organizations
export CORE_PEER_TLS_ENABLED=true
export PATH=${FABRIC_PATH}/bin:$PATH
maven集成fabric-chaincode-shim津坑,實(shí)現(xiàn)區(qū)塊鏈智能合約
一护戳、pom.xml 添加依賴
<repositories>
<repository>
<id>central</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://www.jitpack.io</url>
</repository>
<repository>
<id>artifactory</id>
<url>https://hyperledger.jfrog.io/hyperledger/fabric-maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.hyperledger.fabric-chaincode-java</groupId>
<artifactId>fabric-chaincode-shim</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.38</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>chaincode</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.hyperledger.fabric.contract.ContractRouter</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<!-- filter out signature files from signed dependencies, else repackaging fails with security ex -->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
二珍特、實(shí)現(xiàn)智能合約代碼
import com.alibaba.fastjson.JSON;
import java.util.Objects;
/**
* 用戶帳戶對(duì)象
*/
public class User {
private String userId;
private String name;
private double money;
public User(final String userId, final String name, final double money) {
this.userId = userId;
this.name = name;
this.money = money;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setName(String name) {
this.name = name;
}
public void setMoney(double money) {
this.money = money;
}
public String getName() {
return name;
}
public double getMoney() {
return money;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
User other = (User) obj;
return Objects.deepEquals(
new String[] {getUserId(), getName()},
new String[] {other.getUserId(), other.getName()})
&&
Objects.deepEquals(
new double[] {getMoney()},
new double[] {other.getMoney()});
}
@Override
public int hashCode() {
return Objects.hash(getUserId(), getName(), getMoney());
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
import com.alibaba.fastjson.JSON;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.*;
import org.hyperledger.fabric.shim.ChaincodeException;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.KeyModification;
import org.hyperledger.fabric.shim.ledger.KeyValue;
import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 智能合約-用戶賬本
*/
@Contract(name = "UserChainCode")
@Default
public class UserChainCode implements ContractInterface {
public UserChainCode() {
}
/**
* 初始化3條記錄
*/
@Transaction(intent = Transaction.TYPE.SUBMIT)
public void init(final Context ctx) {
addUser(ctx, "1", "mixm",100D);
addUser(ctx, "2", "admin",200D);
addUser(ctx, "3", "user",300D);
}
/**
* 獲取該id的所有變更記錄
*/
@Transaction(intent = Transaction.TYPE.EVALUATE)
public String getHistory(final Context ctx, final String userId) {
Map<String, String> userHistory = new HashMap<>();
ChaincodeStub stub = ctx.getStub();
QueryResultsIterator<KeyModification> iterator = stub.getHistoryForKey(userId);
for (KeyModification result: iterator) {
userHistory.put(result.getTxId(), result.getStringValue());
}
return JSON.toJSONString(userHistory);
}
/**
* 新增用戶
*/
@Transaction(intent = Transaction.TYPE.SUBMIT)
public String addUser(final Context ctx, final String userId, final String name, final double money) {
ChaincodeStub stub = ctx.getStub();
User user = new User(userId, name, money);
String userJson = JSON.toJSONString(user);
stub.putStringState(userId, userJson);
return stub.getTxId();
}
/**
* 查詢某個(gè)用戶
*/
@Transaction(intent = Transaction.TYPE.EVALUATE)
public User getUser(final Context ctx, final String userId) {
ChaincodeStub stub = ctx.getStub();
String userJSON = stub.getStringState(userId);
if (userJSON == null || userJSON.isEmpty()) {
String errorMessage = String.format("User %s does not exist", userId);
throw new ChaincodeException(errorMessage);
}
return JSON.parseObject(userJSON, User.class);
}
/**
* 查詢所有用戶
*/
@Transaction(intent = Transaction.TYPE.EVALUATE)
public String queryAll(final Context ctx) {
ChaincodeStub stub = ctx.getStub();
List<User> userList = new ArrayList<>();
QueryResultsIterator<KeyValue> results = stub.getStateByRange("", "");
for (KeyValue result: results) {
User user = JSON.parseObject(result.getStringValue(), User.class);
System.out.println(user);
userList.add(user);
}
return JSON.toJSONString(userList);
}
/**
* 轉(zhuǎn)賬
* @param sourceId 源用戶id
* @param targetId 目標(biāo)用戶id
* @param money 金額
*/
@Transaction(intent = Transaction.TYPE.SUBMIT)
public String transfer(final Context ctx, final String sourceId, final String targetId, final double money) {
ChaincodeStub stub = ctx.getStub();
User sourceUser = getUser(ctx, sourceId);
User targetUser = getUser(ctx, targetId);
if (sourceUser.getMoney() < money) {
String errorMessage = String.format("The balance of user %s is insufficient", sourceId);
throw new ChaincodeException(errorMessage);
}
User newSourceUser = new User(sourceUser.getUserId(), sourceUser.getName(), sourceUser.getMoney() - money);
User newTargetUser = new User(targetUser.getUserId(), targetUser.getName(), targetUser.getMoney() + money);
stub.putStringState(sourceId, JSON.toJSONString(newSourceUser));
stub.putStringState(targetId, JSON.toJSONString(newTargetUser));
return stub.getTxId();
}
}
- 打包合約源碼
peer lifecycle chaincode package UserChainCode.tar.gz --path /工程目錄/UserChainCode --lang java --label UserChainCode
三芦缰、安裝合約
- 設(shè)置peer0.org1環(huán)境:
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${MSP_PATH}/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
??安裝合約:
peer lifecycle chaincode install UserChainCode.tar.gz
??成功返回值:
[2022-06-16 02:01:41.891 PDT [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nNUserChainCode:c8afcba20a3e5e70b1ca183a983d856e984908f02bc0244f4be0755940745271\022\rUserChainCode" >
2022-06-16 02:01:41.891 PDT [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: UserChainCode:c8afcba20a3e5e70b1ca183a983d856e984908f02bc0244f4be0755940745271
- ??設(shè)置peer0.org2環(huán)境:
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${MSP_PATH}/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${MSP_PATH}/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
??安裝合約:
peer lifecycle chaincode install UserChainCode.tar.gz
- 查看安裝的合約清單:
peer lifecycle chaincode queryinstalled
四、合約審核
當(dāng)合約安裝后,需經(jīng)過機(jī)構(gòu)的審批達(dá)成一致后才允許使用西壮。
package-id通過合約清單查詢
- peer0.org1審核合約
??環(huán)境變量設(shè)置
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${MSP_PATH}/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
??審批合約
peer lifecycle chaincode approveformyorg \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile ${MSP_PATH}/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
--channelID mychannel \
--name UserChainCode \
--version 1.0 \
--package-id UserChainCode:c8afcba20a3e5e70b1ca183a983d856e984908f02bc0244f4be0755940745271 \
--sequence 1
??成功返回值:
2022-06-16 02:17:23.850 PDT [chaincodeCmd] ClientWait -> INFO 001 txid [f657a862e0f08e14429c31c660b1db798ee4099f21006b67f26e939c22510c9b] committed with status (VALID) at localhost:7051
- peer0.org2審核合約
??設(shè)置環(huán)境:
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${MSP_PATH}/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${MSP_PATH}/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
??審批合約
peer lifecycle chaincode approveformyorg \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile ${MSP_PATH}/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
--channelID mychannel \
--name UserChainCode \
--version 1.0 \
--package-id UserChainCode:c8afcba20a3e5e70b1ca183a983d856e984908f02bc0244f4be0755940745271 \
--sequence 1
??成功返回值:
2022-06-16 02:13:17.149 PDT [chaincodeCmd] ClientWait -> INFO 001 txid [c7824a195ab4734421a452546334b10ed1e3043de947bd43e02afce692fa32b9] committed with status (VALID) at localhost:9051
- 檢查合約的審批情況
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name UserChainCode --version 1.0 --sequence 1 --output json
??成功返回值:
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
五、提交合約
- 向通道提交合約
peer lifecycle chaincode commit \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile ${MSP_PATH}/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
--channelID mychannel \
--name UserChainCode \
--peerAddresses localhost:7051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
--version 1.0 \
--sequence 1
??成功返回:
2022-06-16 02:24:00.916 PDT [chaincodeCmd] ClientWait -> INFO 001 txid [a98706144cb7a982924935d175d3d9469a1ba384918fa3b2317796ab5c9fc45b] committed with status (VALID) at localhost:9051
2022-06-16 02:24:00.922 PDT [chaincodeCmd] ClientWait -> INFO 002 txid [a98706144cb7a982924935d175d3d9469a1ba384918fa3b2317796ab5c9fc45b] committed with status (VALID) at localhost:7051
- 查看通道上已提交合約
peer lifecycle chaincode querycommitted --channelID mychannel --name UserChainCode --output json
??成功返回:
{
"sequence": 1,
"version": "1.0",
"endorsement_plugin": "escc",
"validation_plugin": "vscc",
"validation_parameter": "EiAvQ2hhbm5lbC9BcHBsaWNhdGlvbi9FbmRvcnNlbWVudA==",
"collections": {},
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
六叫惊、測(cè)試合約
- 初始化賬本
peer chaincode invoke -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile ${MSP_PATH}/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel \
-n UserChainCode \
--peerAddresses localhost:7051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c '{"function":"init","Args":[]}'
??成功返回:
2022-06-16 02:32:17.327 PDT [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
- 查詢數(shù)據(jù)
??設(shè)置為peer0.org1環(huán)境
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${MSP_PATH}/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
??查詢所有數(shù)據(jù)
peer chaincode query -C mychannel -n UserChainCode -c '{"Args":["queryAll"]}'
??成功返回:
[{"money":100.0,"name":"mixm","userId":"1"},{"money":200.0,"name":"admin","userId":"2"},{"money":300.0,"name":"user","userId":"3"}]
??單個(gè)查詢
peer chaincode query -C mychannel -n UserChainCode -c '{"Args":["getUser", "1"]}'
??成功返回:
- 新增數(shù)據(jù)
peer chaincode invoke -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile ${MSP_PATH}/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel \
-n UserChainCode \
--peerAddresses localhost:7051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c '{"function":"addUser","Args":["4","test","400"]}'
??成功返回:
2022-06-16 04:45:33.799 PDT [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"3fec668b3342100ca362fc342d240cc5bc6fb1e52cced55233b4a984f4d13c3a"
- 轉(zhuǎn)賬
peer chaincode invoke -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile ${MSP_PATH}/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel \
-n UserChainCode \
--peerAddresses localhost:7051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 \
--tlsRootCertFiles ${MSP_PATH}/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c '{"function":"transfer","Args":["4","1","400"]}'
??成功返回:
2022-06-16 04:48:05.651 PDT [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"5bfd15030101eb1fd538ffd622d8a66c79d237fabeaaa67342ee8ba04dc1dccc"