Fabric实战(2)- Commercial Paper的Fabric-Java-SDK客户端

转自独立博客simplexity.cn

到目前为止都是通过在cli容器执行peer chaincode命令调用chaincode,实际上官方提供SDK(当前只有Node.js和Java两种)。这里提供基于Fabric Java SDK的commercial paper客户端,设置使用TLS,详细项目代码在github。项目采用Springboot,swagger提供网页调用。注意,这里只是demo,不能作为生产环境使用。具体步骤大致拆解如下:

  1. 构建HFClient
public HFClient getObject() throws Exception {
    // 使用Org1的admin用户身份。由于使用TSL,这里提供keyFile:admin的私钥和certFile:由ca.org1.example.com签发的证书
    // 也可以通过使用HFCAClient向ca发送enroll和register请求用于新增注册和登记身份证书。具体可以参看参考文档。
    Enrollment enrollment = PaperUser.createEnrollmentFromPemFile(keyFile, certFile);
    PaperUser admin = new PaperUser(name, mspId, enrollment);

    HFClient client = HFClient.createNewInstance();
    client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
    client.setUserContext(admin);
    initChannel();
    return client;
}

protected static Enrollment createEnrollmentFromPemFile(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对象
}

// 使用TSL,需要提供peerTLScaCertFile:tlsca.org1.example.com的证书和ordererTLScaCertFile:tlsca.example.com的证书
private void initChannel() throws Exception {
    Channel channel = client.newChannel(channelID);
    Properties peerProps = new Properties();
    peerProps.put("pemFile", peerTLScaCertFile);
    peerProps.setProperty("sslProvider", "openSSL");
    peerProps.setProperty("negotiationType", "TLS");
    Peer peer = client.newPeer(peerName, peerURL, peerProps);
    channel.addPeer(peer);

    Properties ordererProps = new Properties();
    ordererProps.put("pemFile", ordererTLScaCertFile);
    ordererProps.setProperty("sslProvider", "openSSL");
    ordererProps.setProperty("negotiationType", "TLS");
    Orderer orderer = client.newOrderer(ordererName, ordererURL, ordererProps);
    channel.addOrderer(orderer);

    channel.initialize();
}
  • peerURL设置为grpcs://peer0.org1.example.com:7051。首先,TLS需要设置使用grpcs。其次,只能使用peer0.org1.example.com(同时需要配置hosts文件),不能使用 127.0.0.1或者localhost(报错Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching IP address 127.0.0.1/localhost found) 。因为peer0返回的证书的CN是peer0.org1.example.com,java ssl会校验这个域名。
  1. chaincode - query
public Result query(String issuer, String paperNumber) {
    QueryByChaincodeRequest req = client.newQueryProposalRequest();
    ChaincodeID cid = ChaincodeID.newBuilder().setName(chaincodeName).build();
    req.setChaincodeID(cid);
    req.setFcn(QUERY_FUNC);
    req.setArgs(issuer, paperNumber);

    // Channel对象已在上面构建
    Channel channel = client.getChannel(channelID);
    Collection<ProposalResponse> propResps = channel.queryByChaincode(req);
    // endorser返回的ProposalResponse需要保持一致
    Collection<Set<ProposalResponse>> proposalConsistencySets = SDKUtils.getProposalConsistencySets(propResps);
    if (proposalConsistencySets.size() != 1) {
        return Result.fail(ErrorCode.CHAINCOED_SERVICE_ERROR)
                .withErrorMsg("Expected only one set of consistent proposal responses but got more");
    }
    FabricProposalResponse.Response res = propResps.iterator().next().getProposalResponse().getResponse();
    if (res.getStatus() == 200) {
        return Result.success().withResponse(res.getPayload().toStringUtf8());
    }
    return Result.fail(ErrorCode.CHAINCOED_SERVICE_ERROR).withErrorMsg(res.getMessage());
}
  1. chaincode - invoke
public Result issue(IssueRequest request) {
    TransactionProposalRequest proposalRequest = client.newTransactionProposalRequest();
    ChaincodeID cid = ChaincodeID.newBuilder().setName(chaincodeName).build();
    proposalRequest.setChaincodeID(cid);
    proposalRequest.setFcn(ISSUE_FUNC);
    proposalRequest.setArgs(request.getIssuer(), request.getPaperNumber(), issueDate, maturityDate,
            String.valueOf(request.getFaceValue()));

    Channel channel = client.getChannel(channelID);
    // Endorsing(simulate) phase
    Collection<ProposalResponse> propResps = channel.sendTransactionProposal(proposalRequest);
    // endorser返回的ProposalResponse需要保持一致
    Collection<Set<ProposalResponse>> proposalConsistencySets = SDKUtils.getProposalConsistencySets(propResps);
    if (proposalConsistencySets.size() != 1) {
        return Result.fail(ErrorCode.CHAINCOED_SERVICE_ERROR)
                .withErrorMsg("Expected only one set of consistent proposal responses but got more");
    }

    // Orderer phase
    // 这里同步调用,需要等到提交orderer并且orderer排序后发送到各个peer,peer处理了block里的交易后才返回。
    // 或者同步返回txid。可以配置eventHub异步接收和执行block,通过txid来返回最终的执行结果
    BlockEvent.TransactionEvent event = channel.sendTransaction(propResps).get();
    if (event.isValid()) {
        return Result.success().withResponse("txid : " + event.getTransactionID());
    }
    return Result.fail(ErrorCode.CHAINCOED_SERVICE_ERROR);
}

WIP:

  1. eventHub

Ref.

Fabric Java SDK最新教程【201904】

你可能感兴趣的:(HyperLedger,Fabric)