美文网首页
fabric1.4.x java-sdk使用

fabric1.4.x java-sdk使用

作者: 区块东西 | 来源:发表于2020-12-01 09:30 被阅读0次

    参考链接

    之前没写过java,第一用java做项目。
    本文主要参考以下链接
    https://www.cnblogs.com/cbkj-xd/p/12112311.html
    https://www.jianshu.com/p/bfb081a96337
    http://blog.hubwiz.com/2019/04/23/fabric-sdk-java-hello-world/
    https://blog.csdn.net/qq_27348837/article/details/95489720
    https://developer.ibm.com/tutorials/hyperledger-fabric-java-sdk-for-tls-enabled-fabric-network/

    sdk-github 可以看看里面的例子,不过封装的好深,我对java也不是很熟,看起来有点费劲。里面很多都是写在配置里,或者在一些类里封装的。


    代码

    先上代码
    参考上面的帖子,需要要实现一个User的类,来实例化一个user对象。

    • LocalUser
    public class LocalUser implements User {
        private boolean TLS_ENABLE = true;
        private String name;
        private String mspID;
        private Enrollment enrollment;
    
        LocalUser(String name, String mspID){
            this.name = name;
            this.mspID = mspID;
        }
    
        LocalUser(String name, String mspID, String keyFile, String certFile) throws Exception{
            this(name, mspID);
            this.enrollment = loadFromPemFile(keyFile, certFile);
    
            if (TLS_ENABLE == true) {
    
    
            }
        }
    
        private Enrollment loadFromPemFile(String keyFile,String certFile) throws Exception{
            byte[] sk = Files.readAllBytes(Paths.get(keyFile));     //载入私钥
            byte[] certPem = Files.readAllBytes(Paths.get(certFile));   //载入证书PEM文本
            CryptoPrimitives suite = new CryptoPrimitives();            //载入密码学套件
            PrivateKey privateKey = suite.bytesToPrivateKey(sk);    //将PEM文本转换为私钥对象
            return new X509Enrollment(privateKey,new String(certPem));  //创建并返回X509Enrollment对象
        }
    
        @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;}
    
        static String getPEMStringFromPrivateKey(PrivateKey privateKey) throws IOException {
            StringWriter pemStrWriter = new StringWriter();
            PEMWriter pemWriter = new PEMWriter(pemStrWriter);
    
            pemWriter.writeObject(privateKey);
    
            pemWriter.close();
    
            return pemStrWriter.toString();
        }
    }
    
    • 我把关键逻辑都封装在 ChainCode.java了
    public class ChainCode {
    
    
    
    
        private static final String Crypto_Config_Path = "D:\\prj\\crypto-config\\";
    
        private static final String CA_Pemfile = Crypto_Config_Path+"peerOrganizations\\org1.example.com\\ca\\ca.org1.example.com-cert.pem";
    
        private String adminKeyFile = Crypto_Config_Path+"peerOrganizations\\" +
                "org1.example.com\\users\\Admin@org1.example.com\\msp\\keystore\\d1bc2f6f9dd1fdc6a90c32f203983870e7189131ca90493281f97bfe87ddcaa8_sk";
        private String adminCertFile = Crypto_Config_Path+"peerOrganizations\\org1.example.com\\users\\Admin@org1.example.com\\" +
                "msp\\signcerts\\Admin@org1.example.com-cert.pem";
    
        private HFClient client;
        private Channel channel;
    
        HFClient InitClient() throws  Exception{
            this.client = HFClient.createNewInstance();
            client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
            client.setUserContext(new LocalUser("admin", "Org1MSP", adminKeyFile, adminCertFile));
    
    
    
            return client;
        }
    
    
        void CreateChannelIns() throws  Exception{
            this.channel = client.newChannel("contractchannel");
    
            Properties proper;
    
            proper = loadTLSFile("peerOrganizations\\org1.example.com\\peers\\peer0.org1.example.com\\msp\\tlscacerts\\tlsca.org1.example.com-cert.pem", "peer0.org1.example.com");
            Peer peer = client.newPeer("peer0.org1.example.com","grpcs://192.169.0.86:7051", proper);
            channel.addPeer(peer);
    
            proper = loadTLSFile("ordererOrganizations\\example.com\\orderers\\orderer1.example.com\\msp\\tlscacerts\\tlsca.example.com-cert.pem", "orderer1.example.com");
            Orderer orderer = client.newOrderer("orderer1.example.com","grpcs://192.169.0.86:7050", proper);
            channel.addOrderer(orderer);
            channel.initialize();
        }
    
        /**
         * 为Fabric网络中节点配置TLS根证书
         *
         * @param rootTLSCert 根证书路径
         * @param hostName    节点域名
         * @return
         * @throws IOException
         */
        private static Properties loadTLSFile(String rootTLSCert, String hostName) throws IOException {
            Properties properties = new Properties();
            properties.put("pemBytes", Files.readAllBytes(Paths.get( Crypto_Config_Path + rootTLSCert)));
            properties.setProperty("sslProvider", "openSSL");
            properties.setProperty("negotiationType", "TLS");
            properties.setProperty("trustServerCertificate", "true");
            properties.setProperty("hostnameOverride", hostName);
            return properties;
        }
    
        void Query() throws Exception{
            QueryByChaincodeRequest req = this.client.newQueryProposalRequest();
            ChaincodeID cid = ChaincodeID.newBuilder().setName("contract").build();
            req.setChaincodeID(cid);
            req.setFcn("query");
            req.setArgs("a");
    //        req.setChaincodeEndorsementPolicy();
            ProposalResponse[] rsp = this.channel.queryByChaincode(req).toArray(new ProposalResponse[0]);
            System.out.format("rsp message => %s\n",rsp[0].getProposalResponse().getResponse().getPayload().toStringUtf8());
        }
    
    }
    
    public class App 
    {
        public static void main( String[] args ) {
            ChainCode c = new ChainCode();
    
            try {
                c.InitClient();
                c.CreateChannelIns();
                c.Query();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    

    注意事项

    网络环境

    fabric 1.4.2
    java-fabric-sdk 2.0.0 release
    未开启fabric-ca服务
    开启TLS

    踩坑
    HFClient

    因为开启了tls,我刚开始看javasdk里面的ene2endit这个示例,以为要用HFCAClient这个类初始化,后面又搜了一圈,发现不用。第一个坑点。只需要HFClient

    User证书
    用户证书结构

    初始化User的时候,传入Admin的私钥,和证书pem。为什么要admin的?这个应该跟policy配置有关,在configtx.yaml中,具体我还没研究过。回头再看

    开启TLS必须配置 peer和orderer证书
    peer证书结构

    这么多证书看着有点乱。我还没完全理解各个证书的关系和作用。
    大概区分一下 msp是用来鉴权的,直白的说就是确定你是不是你,主要用来确认身份用的。
    tls是加密通讯的证书,跟区块链的身份鉴权是两个东西,别混淆了(我暂时是这么理解的)。
    需注意tls/ca.crt 跟
    msp/tlscacerts/tlsca.org1.xxx.com-cert.pem 内容是一样的。
    用于tls通讯的根证书。所以在传入根证书的时候,两个任意一个都可以。

    properties.put("pemBytes", Files.readAllBytes(Paths.get( Crypto_Config_Path + rootTLSCert)));
    properties.put("pemFile", Paths.get( Crypto_Config_Path + rootTLSCert));
    

    上面的代码,二选一都可以,不一定要传入字符串。

    报错处理
    org.hyperledger.fabric.sdk.exception.ProposalException: 
    org.hyperledger.fabric.sdk.exception.TransactionException: 
    org.hyperledger.fabric.sdk.exception.ProposalException:
     getConfigBlock for channel contractchannel failed with peer peer0.org1.example.com.  Status FAILURE, details:
     Channel Channel{id: 1, name: contractchannel} Sending proposal with transaction: 
    d795243d5dc706d8d7b2baafe7cdcf66343cd83d93aeb23c3363124724ea54de to Peer{ id: 2, name: peer0.org1.example.com, channelName:
     contractchannel, url: grpc://192.169.0.86:7051} failed because of:
     gRPC failure=Status{code=INTERNAL, description=http2 exception, cause=io.netty.handler.codec.http2.Http2Exception:
     First received frame was not SETTINGS. Hex dump for first 5 bytes: 1503010002
    

    百度谷歌了一圈,确认不了是什么问题,但是隐约觉得是tls的配置问题。
    查看peer0的日志,发现了问题所在。

     docker logs 23ef8ad2f248 -t --since="2020-04-01" --tail=50
    

    查看peer0最后50条日志。

    2020-04-01T03:41:03.038774384Z 2020-04-01 03:41:03.038 UTC [core.comm]
     ServerHandshake ->
     ERRO 10f8 TLS handshake failed with error tls: first record does not look like a TLS handshake
     {"server": "PeerServer", "remote address": "192.169.0.145:62931"}
    

    不是TLS握手,说明tls有问题。
    其实是个很小的问题,特别容易忽略,在看别人代码的时候,我就注意到有个地方很奇怪。

    Peer peer = client.newPeer("peer0.org1.example","grpcs://192.169.0.86:7051", proper);
    

    注意url,必须写grpcs,而不是grpc!
    之前我就注意到,有点例子里面写的是grpc,有的写的是grpcs。加上s,完美解决。

    相关文章

      网友评论

          本文标题:fabric1.4.x java-sdk使用

          本文链接:https://www.haomeiwen.com/subject/ykrouhtx.html