Fabric java sdk 1.4簡明教程
在超級賬本Fabric區塊鏈中,應用通過節點的RPC協議介面訪問鏈碼。Java應用可以使用官方提供的Fabric-sdk-java開發包來實現對鏈碼的訪問,開發包封裝了Fabric區塊鏈的GRPC鏈碼訪問協議,有利於開發人員聚焦於業務邏輯。不過Fabric-sdk-java的文件質量保持了Hyperledger Fabric產品一貫的不知所云,看起來實在是令人捉急。本文將嘗試編寫一個最簡單的可以訪問Fabric鏈碼的Java應用,來幫助你快速上手Farbic區塊鏈的Java應用開發。
如果希望快速掌握Fabric區塊鏈的鏈碼及應用開發,建議訪問匯智網的線上互動課程:
基本原理
在Fabric區塊鏈中,應用通過節點的RPC協議介面訪問鏈碼:
類似於Shim API對鏈碼通訊協議的封裝,Fabric Java SDK提供了 對節點RPC協議介面的封裝,其入口類為HFClient,對鏈碼的查詢和交易操作則 封裝在Channel類中:
由於Fabric是許可制區塊鏈,因此應用也需要持有證書和私鑰以表徵自己的身份,HFClient例項依賴於User介面的實現物件來訪問一個特定身份的證書和私鑰,因此在訪問 鏈碼之前,我們需要首先定義一個簡單的User介面實現類。
實現User介面
HFClient
例項訪問Fabric網路的身份使用User
LocalUser
:
容易理解,一個使用者的身份是由它的證書來標識的,同時交易還需要證書對應的私鑰,因此LocalUser的核心邏輯就是利用指定的證書和私鑰PEM檔案滿足User介面的要求。
首先按照User介面的要求完成類LocalUser
的骨架:
import org.hyperledger.fabric.sdk.User; import org.hyperledger.fabric.sdk.security.CryptoPrimitives; public class LocalUser implements User{ //實現User介面 private String name; private String mspId; private Enrollment enrollment; LocalUser(String name,String mspId){ this.name = name; this.mspId = mspId; } private Enrollment loadFromPemFile(String keyFile,String certFile){ /*見下文說明*/ } @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; } }
在Fabric Java SDK中,Enrollment
介面用來提供對使用者的私鑰和證書的訪問,並且預置了一個適合X509證書的實現類X509Enrollment
,因此我們可以從本地MSP目錄中的PEM檔案中載入使用者私鑰和簽名證書:
private Enrollment loadFromPemFile(String keyFile,String certFile) throws Exception{
byte[] keyPem = Files.readAllBytes(Paths.get(keyFile)); //載入私鑰PEM文字
byte[] certPem = Files.readAllBytes(Paths.get(certFile)); //載入證書PEM文字
CryptoPrimitives suite = new CryptoPrimitives(); //載入密碼學套件
PrivateKey privateKey = suite.bytesToPrivateKey(keyPem); //將PEM文字轉換為私鑰物件
return new X509Enrollment(privateKey,new String(certPem)); //建立並返回X509Enrollment物件
}
訪問鏈碼
有了User介面實現類,接下來只要建立一個HFClient例項,然後獲取通道物件,就可以查詢鏈碼,或者提交鏈碼交易了。
完整的實現程式碼如下:
package com.hubwiz.demo;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.Orderer;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
import org.hyperledger.fabric.sdk.ChaincodeID;
import org.hyperledger.fabric.sdk.QueryByChaincodeRequest;
import org.hyperledger.fabric.sdk.ProposalResponse;
import org.hyperledger.fabric.sdk.TransactionProposalRequest;
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
public class App{
public static void main(String[] args) throws Exception{
System.out.println("counter app");
//建立User例項
String keyFile = "../solo-network/msp/keystore/user-key.pem";
String certFile = "../solo-network/msp/signcerts/user-cert.pem";
LocalUser user = new LocalUser("admin","SampleOrg",keyFile,certFile);
//建立HFClient例項
HFClient client = HFClient.createNewInstance();
client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
client.setUserContext(user);
//建立通道例項
Channel channel = client.newChannel("ch1");
Peer peer = client.newPeer("peer1`","grpc://127.0.0.1:7051");
channel.addPeer(peer);
Orderer orderer = client.newOrderer("orderer1","grpc://127.0.0.1:7050");
channel.addOrderer(orderer);
channel.initialize();
//查詢鏈碼
QueryByChaincodeRequest req = client.newQueryProposalRequest();
ChaincodeID cid = ChaincodeID.newBuilder().setName("counter-cc").build();
req.setChaincodeID(cid);
req.setFcn("value");
ProposalResponse[] rsp = channel.queryByChaincode(req).toArray(new ProposalResponse[0]);
System.out.format("rsp message => %s\n",rsp[0].getProposalResponse().getResponse().getPayload().toStringUtf8());
//提交鏈碼交易
TransactionProposalRequest req2 = client.newTransactionProposalRequest();
req2.setChaincodeID(cid);
req2.setFcn("inc");
req2.setArgs("10");
Collection<ProposalResponse> rsp2 = channel.sendTransactionProposal(req2);
TransactionEvent event = channel.sendTransaction(rsp2).get();
System.out.format("txid: %s\n", event.getTransactionID());
System.out.format("valid: %b\n", event.isValid());
}
}
匯智網原創,