借鉴网上的一篇博文,实现向fabric区块链上存入数据摘要并查询最新的数据记录。
使用的fabric1.4.1单机单节点网络,采用solo共识(多机kafka共识环境也可使用);采用docker部署;关闭TLS;chaincode采用Java编写;fabric状态数据库为couchdb使用了数据库索引;fabric-sdk-java依赖版本为1.4.1。
建议有一定fabric基础的同学食用。
笔者使用的fabric的单机单节点网络实例://download.csdn.net/download/weixin_43562234/12116307
博客园不支持资源上传,非常抱歉~~~~~
1.App.class
package com.richfit.fabric;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import com.alibaba.fastjson.JSONObject;
import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
/**
* Hello world!
*/
public class App {
public static void main(String[] args) throws Exception {
Configurations configurations = new Configurations();
HFClient client = HFClient.createNewInstance();
Channel channel = initChannel(client,configurations);
//query
queryByChaincode(client,configurations,channel);
//insert
/*for (int i = 0; i <3; i++) {
Business business = new Business();
business.setBizUUID("test");
business.setBizType("test");
business.setFillPerson("test");
business.setSubmissionTim("test");
business.setReviewer("test");
business.setReviewOpinion("test");
business.setReviewPass("test");
business.setToGzwTime("test");
business.setRequestTime("test");
business.setCount(i);
business.setRequestID("test");
//Thread.sleep(1000);
System.out.println("messageCount: "+i);
String json = JSON.toJSONString(business);
insertBlockChain(client,configurations,channel,json);
}*/
}
/**
* @description query
* @params [client, configurations, channel]
* @return void
* @author adder
* @date 2020/1/20 14:23
*
*/
public static void queryByChaincode(HFClient client,Configurations configurations,Channel channel) throws FileNotFoundException, ProposalException, InvalidArgumentException, UnsupportedEncodingException {
String chaincodeName = configurations.loadConfigurations().getJsonObject("options").getString("chaincode_id");
ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(chaincodeName).build();
//build args
ArrayList<String> argsList = new ArrayList<>();
argsList.add("test");
argsList.add("test");
//build query request
QueryByChaincodeRequest request = client.newQueryProposalRequest();
request.setChaincodeID(chaincodeID);
request.setFcn("query");
request.setArgs(argsList);
Collection<ProposalResponse> responses = channel.queryByChaincode(request);
ProposalResponse response = (ProposalResponse) responses.toArray()[0];
//analyse response
if (response.getStatus().toString().equals("SUCCESS")){
System.out.println(response.getChaincodeActionResponseStatus());
String result = new String(response.getChaincodeActionResponsePayload(), StandardCharsets.UTF_8);
System.out.println(result);
JSONObject json = JSONObject.parseObject(result);
String returnCode = (String) json.get("returnCode");
System.out.println(returnCode);
}
}
public static void insertBlockChain(HFClient client,Configurations configurations,Channel channel,String message) throws FileNotFoundException, InvalidArgumentException, ProposalException, ExecutionException, InterruptedException {
String chaincodeName = configurations.loadConfigurations().getJsonObject("options").getString("chaincode_id");
ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(chaincodeName).build();
JSONObject msgJson = JSONObject.parseObject(message);
msgJson.put("blockTimeTamp",System.currentTimeMillis());
//build args
ArrayList<String> argsList = new ArrayList<>();
argsList.add(msgJson.toJSONString());
//build insert request
TransactionProposalRequest request = client.newTransactionProposalRequest();
request.setChaincodeLanguage(TransactionRequest.Type.JAVA);
request.setChaincodeID(chaincodeID);
request.setArgs(argsList);
request.setFcn("insert");
Collection<ProposalResponse> responses = channel.sendTransactionProposal(request);
CompletableFuture<TransactionEvent> transactionEvent = channel.sendTransaction(responses);
TransactionEvent event = transactionEvent.get();
System.out.println(event.getTransactionID());
System.out.println(event.isValid());
}
/**
* @description
* @params [client, configurations]
* @return org.hyperledger.fabric.sdk.Channel
* @author adder
* @date 2020/1/20 14:27
*
*/
private static Channel initChannel(HFClient client,Configurations configurations) throws Exception {
//create user object
String keyDir = configurations.loadConfigurations().getJsonObject("options").getString("privateKeyFolder");
String keyFile = getKeyFilesInDir(new File(keyDir)).toString();
String certFile = configurations.loadConfigurations().getJsonObject("options").getString("signedCert");
String userName = configurations.loadConfigurations().getJsonObject("options").getString("user_id");
String mspId = configurations.loadConfigurations().getJsonObject("options").getString("msp_id");
String channelName = configurations.loadConfigurations().getJsonObject("options").getString("channel_id");
String peerName = configurations.loadConfigurations().getJsonObject("options").getString("peer_server_hostname");
String peerURL = configurations.loadConfigurations().getJsonObject("options").getString("peer_url");
String ordererName = configurations.loadConfigurations().getJsonObject("options").getString("orderer_server_hostname");
String ordererURL = configurations.loadConfigurations().getJsonObject("options").getString("orderer_url");
FabricUser user = new FabricUser(userName, mspId, keyFile, certFile);
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
client.setUserContext(user);
//create channel object
Channel channel = client.newChannel(channelName);
//create peer
Peer peer = client.newPeer(peerName, peerURL);
channel.addPeer(peer);
//orderer
Orderer orderer = client.newOrderer(ordererName, ordererURL);
channel.addOrderer(orderer);
channel.initialize();
return channel;
}
/**
* @description get private key from key dir
* @params [filePath]
* @return java.io.File
* @author adder
* @date 2020/1/20 11:02
*
*/
private static File getKeyFilesInDir(File filePath) {
File keyFile = null;
File[] listFiles = filePath.listFiles();
if(listFiles != null) {
for(File file:listFiles) {
if(file.isFile()) {
if(file.getName().endsWith("_sk")) {
keyFile = file;
break;
}
}
}
}
return keyFile;
}
}
2.Business.class
package com.richfit.fabric;
import lombok.Data;
@Data
public class Business {
public String getRequestID() {
return requestID;
}
public void setRequestID(String requestID) {
this.requestID = requestID;
}
private String requestID;
private String bizUUID;
private String bizType;
private String fillPerson;
private String submissionTim;
private String reviewer;
private String reviewOpinion;
private String reviewPass;
private String toGzwTime;
private int count;
private String requestTime;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getBizUUID() {
return bizUUID;
}
public void setBizUUID(String bizUUID) {
this.bizUUID = bizUUID;
}
public String getBizType() {
return bizType;
}
public void setBizType(String bizType) {
this.bizType = bizType;
}
public String getFillPerson() {
return fillPerson;
}
public void setFillPerson(String fillPerson) {
this.fillPerson = fillPerson;
}
public String getSubmissionTim() {
return submissionTim;
}
public void setSubmissionTim(String submissionTim) {
this.submissionTim = submissionTim;
}
public String getReviewer() {
return reviewer;
}
public void setReviewer(String reviewer) {
this.reviewer = reviewer;
}
public String getReviewOpinion() {
return reviewOpinion;
}
public void setReviewOpinion(String reviewOpinion) {
this.reviewOpinion = reviewOpinion;
}
public String getReviewPass() {
return reviewPass;
}
public void setReviewPass(String reviewPass) {
this.reviewPass = reviewPass;
}
public String getToGzwTime() {
return toGzwTime;
}
public void setToGzwTime(String toGzwTime) {
this.toGzwTime = toGzwTime;
}
public String getRequestTime() {
return requestTime;
}
public void setRequestTime(String requestTime) {
this.requestTime = requestTime;
}
}
3.Configurations.class
package com.richfit.fabric;
import org.yaml.snakeyaml.Yaml;
import javax.json.Json;
import javax.json.JsonObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;
public class Configurations {
public JsonObject loadConfigurations() throws FileNotFoundException {
String configPath = "src/main/java/com/richfit/fabric/configure/configure.yml";
InputStream stream = new FileInputStream(new File(configPath));
Yaml yaml = new Yaml();
Map<String,Object> configYaml = yaml.load(stream);
JsonObject configJSON = Json.createObjectBuilder(configYaml).build();
return configJSON;
}
}
4.FabricUser.class
package com.richfit.fabric;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.Set;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.identity.X509Enrollment;
import org.hyperledger.fabric.sdk.security.CryptoPrimitives;
public class FabricUser implements User {
private String name;
private String mspId;
private Enrollment enrollment;
private String keyFile;
private String certFile;
FabricUser(String name, String mspId, String keyFile, String certFile) {
this.name = name;
this.mspId = mspId;
this.keyFile=keyFile;
this.certFile=certFile;
try{
enrollment=loadFromPemFile(keyFile, certFile);
}catch(Exception ex){
ex.printStackTrace();
}
}
private Enrollment loadFromPemFile(String keyFile,String certFile) throws Exception{
byte[] keyPem = Files.readAllBytes(Paths.get(keyFile)); //load private key text
byte[] certPem = Files.readAllBytes(Paths.get(certFile)); //load certificate text
CryptoPrimitives suite = new CryptoPrimitives(); //load the cryptography suite
PrivateKey privateKey = suite.bytesToPrivateKey(keyPem); //convert private key text to object
return new X509Enrollment(privateKey,new String(certPem)); //create X509Enrollment object
}
@Override
public String getName() {
return name;
}
@Override
public String getMspId() {
return mspId;
}
@Override
public Enrollment getEnrollment() {
return enrollment;
}
@Override
public String getAccount() {
return null;
}
@Override
public String getAffiliation() {
return null;
}
@Override
public Set<String> getRoles() {
return null;
}
public String getKeyFile() {
return keyFile;
}
public void setKeyFile(String keyFile) {
this.keyFile = keyFile;
}
public String getCertFile() {
return certFile;
}
public void setCertFile(String certFile) {
this.certFile = certFile;
}
}
5.configure.yml
options:
user_id: "Admin@org1.gzjg.com"
msp_id: "Org1MSP"
channel_id: "mychannel"
chaincode_id: "mycc"
peer_url: "grpc://192.168.43.66:7051"
orderer_url: "grpc://192.168.43.66:7050"
privateKeyFolder: "src/main/java/com/richfit/fabric/configure/crypto-config/peerOrganizations/org1.gzjg.com/users/Admin@org1.gzjg.com/msp/keystore/"
signedCert: "src/main/java/com/richfit/fabric/configure/crypto-config/peerOrganizations/org1.gzjg.com/users/Admin@org1.gzjg.com/msp/signcerts/Admin@org1.gzjg.com-cert.pem"
peer_tls_cacerts: "src/main/java/com/richfit/fabric/configure/crypto-config/peerOrganizations/org1.gzjg.com/peers/peer0.org1.gzjg.com/tls/ca.crt"
orderer_tls_cacerts: "src/main/java/com/richfit/fabric/configure/crypto-config/ordererOrganizations/gzjg.com/orderers/orderer.gzjg.com/tls/ca.crt"
peer_server_hostname: "peer0.org1.gzjg.com"
orderer_server_hostname: "orderer.gzjg.com"
6.fabric-chaincode-java
package org.hyperledger.fabric.example;
import java.io.UnsupportedEncodingException;
import java.util.*;
import com.alibaba.fastjson.JSON;
import com.google.protobuf.ByteString;
import io.netty.handler.ssl.OpenSsl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.KeyValue;
import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SimpleChaincode extends ChaincodeBase {
private static Log _logger = LogFactory.getLog(SimpleChaincode.class);
@Override
public Response init(ChaincodeStub stub) {
try {
_logger.info("Init java simpleS chaincode");
String func = stub.getFunction();
if (!func.equals("init")) {
return newErrorResponse("function other than init is not supported");
}
List<String> args = stub.getParameters();
String account1Key = args.get(0);
System.out.println(account1Key);
String account1Value = args.get(1);
System.out.println(account1Value);
_logger.info(String.format("account %s, value = %s", account1Key, account1Value));
return newSuccessResponse();
} catch (Throwable e) {
return newErrorResponse(e);
}
}
@Override
public Response invoke(ChaincodeStub stub) {
try {
_logger.info("Invoke java simple chaincode");
String func = stub.getFunction();
List<String> params = stub.getParameters();
if (func.equals("invoke")) {
return invoke(stub, params);
}
if (func.equals("delete")) {
return delete(stub, params);
}
if (func.equals("query")) {
return query(stub, params);
}
if (func.equals("insert")) {
return insert(stub, params);
}
return newErrorResponse(
"Invalid invoke function name. Expecting one of: [\"invoke\", \"delete\", \"query\"]");
} catch (Throwable e) {
return newErrorResponse(e);
}
}
private Response insert(ChaincodeStub stub, List<String> args) throws UnsupportedEncodingException {
String msgkey = UUID.randomUUID().toString();
// String msgKey =args.get(0);
String msgValue = args.get(0);
stub.putState(msgkey, msgValue.getBytes(UTF_8));
return newSuccessResponse("insert finished successfully",
ByteString.copyFrom(msgkey + ": " + msgValue, UTF_8).toByteArray());
}
private Response invoke(ChaincodeStub stub, List<String> args) {
String msgKey = args.get(0);
String msgValue = args.get(1);
stub.putStringState(msgKey, msgValue);
return newSuccessResponse("invoke finished successfully",
ByteString.copyFrom(msgKey + ": " + msgValue, UTF_8).toByteArray());
}
// Deletes an entity from state
private Response delete(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting 1");
}
String key = args.get(0);
// Delete the key from the state in ledger
stub.delState(key);
return newSuccessResponse();
}
/*
* query callback representing the query of a chaincode rich query
*/
private Response query(ChaincodeStub stub, List<String> args) {
System.out.println("agrs: "+args);
try {
long start = System.currentTimeMillis();
if (args.size() != 2) {
return newErrorResponse(
"Incorrect number of arguments. Expecting name of the person to query");
}
// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
String args1 = args.get(0);
String args2 = args.get(1);
// test
String sql = String.format(
"{\"selector\":{\"bizUUID\": \"%s\",\"bizType\":\"%s\"},\"sort\":[{\"blockTimeTamp\":\"desc\"}]}",
args.get(0), args.get(1));
_logger.info("sql: " + sql);
// QueryResultsIterator<KeyValue> dataResult = stub.getQueryResult(sql);
QueryResultsIteratorWithMetadata<KeyValue> dataResult = stub.getQueryResultWithPagination(sql,
50, "");
_logger.info("query 1: " + (System.currentTimeMillis() - start));
System.out.println("dataResult.iterator().hasNext(): " + dataResult.iterator().hasNext());
if (dataResult.iterator().hasNext()) {
List<String> dataList = new ArrayList();
while (dataResult.iterator().hasNext()) {
KeyValue dr = dataResult.iterator().next();
String drKey = dr.getKey();
String drValue = dr.getStringValue();
System.out.println("drKey: " + drKey + " \n" + "drValue: " + drValue);
dataList.add(drValue);
}
_logger.info("query 2: " + (System.currentTimeMillis() - start));
_logger.info("dataList.size(): " + dataList.size());
_logger.info("query 3: " + (System.currentTimeMillis() - start));
_logger.info("dataList: " + dataList.get(0));
Map<String, String> resultMap = new HashMap<>();
resultMap.put("returnCode", "success");
resultMap.put("result", dataList.get(0));
String jsonString = JSON.toJSONString(resultMap);
_logger.info(String.format("Query Response:\n %s", jsonString));
return newSuccessResponse(String.valueOf(jsonString),
ByteString.copyFrom(String.valueOf(jsonString), UTF_8).toByteArray());
} else {
String result = String.format("State for [bizUUID= %s , bizType= %s] is null", args1,
args2);
Map<String, String> resulMap = new HashMap<>();
resulMap.put("returnCode", "no data");
resulMap.put("result", result);
String jsonString = JSON.toJSONString(resulMap);
return newSuccessResponse(String.valueOf(jsonString),
ByteString.copyFrom(String.valueOf(jsonString), UTF_8).toByteArray());
}
} catch (Exception e) {
return newErrorResponse("query error : " + e);
}
}
public static void main(String[] args) {
System.out.println("OpenSSL avaliable: " + OpenSsl.isAvailable());
new SimpleChaincode().start(args);
}
}
原文:https://www.cnblogs.com/adderhuang/p/12220611.html