在超级帐本Fabric区块链中,应用经过节点的RPC协议接口访问链码。Java应用可使用官方提供的Fabric-sdk-java开发包来实现对链码的访问,java开发包封装了Fabric区块链的GRPC链码访问协议,有利于开发人员聚焦于业务逻辑。本文将经过编写一个最简单的能够访问Fabric链码的Java应用,来帮助你快速上手Fabric区块链的Java应用开发。java
若是但愿快速掌握Fabric区块链的链码及应用开发,建议访问汇智网的在线互动课程:网络
在Fabric区块链中,应用经过节点的RPC协议接口访问链码:app
相似于Shim API对链码通讯协议的封装,Fabric Java SDK提供了 对节点RPC协议 接口的封装,其入口类为HFClient,对链码的查询和交易操做则 封装在Channel类中:ide
因为Fabric是许可制区块链,所以应用也须要持有证书和私钥以表征本身的身份,HFClient实例 依赖于User接口的实现对象 来访问一个特定身份的证书和私钥,所以在访问 链码以前,咱们须要首先定义一个简单的User接口实现类。区块链
HFClient
实例访问Fabric网络的身份使用User
接口实现对象来表征,所以咱们须要定义一个简单的 User接口实现类LocalUser
:ui
容易理解,一个用户的身份是由它的证书来标识的,同时交易还须要证书对应的私钥,所以LocalUser 的核心逻辑就是利用指定的证书和私钥PEM文件知足User接口的要求。this
首先按照User接口的要求完成类LocalUser
的骨架:code
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文件中载入用户私钥和签名证书:orm
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()); } }