package org.hyperledger.fabric.sdk.aberic; import static java.nio.charset.StandardCharsets.UTF_8; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import org.apache.commons.codec.binary.Hex; import org.hyperledger.fabric.protos.ledger.rwset.kvrwset.KvRwset; import org.hyperledger.fabric.sdk.BlockEvent; import org.hyperledger.fabric.sdk.BlockInfo; import org.hyperledger.fabric.sdk.BlockInfo.EnvelopeInfo; import org.hyperledger.fabric.sdk.BlockInfo.EnvelopeType; import org.hyperledger.fabric.sdk.BlockInfo.TransactionEnvelopeInfo; import org.hyperledger.fabric.sdk.aberic.bean.Chaincode; import org.hyperledger.fabric.sdk.aberic.bean.Orderers; import org.hyperledger.fabric.sdk.aberic.bean.Peers; import org.hyperledger.fabric.sdk.BlockListener; import org.hyperledger.fabric.sdk.ChaincodeID; import org.hyperledger.fabric.sdk.Channel; import org.hyperledger.fabric.sdk.HFClient; import org.hyperledger.fabric.sdk.ProposalResponse; import org.hyperledger.fabric.sdk.QueryByChaincodeRequest; import org.hyperledger.fabric.sdk.SDKUtils; import org.hyperledger.fabric.sdk.TransactionProposalRequest; import org.hyperledger.fabric.sdk.TxReadWriteSetInfo; import org.hyperledger.fabric.sdk.exception.CryptoException; import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; import org.hyperledger.fabric.sdk.exception.ProposalException; import org.hyperledger.fabric.sdk.exception.TransactionException; import org.hyperledger.fabric.sdk.security.CryptoSuite; import org.hyperledger.fabric.sdk.util.DateUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; public class ChaincodeManager { private static Logger log = LoggerFactory.getLogger(ChaincodeManager.class); private FabricConfig config; private Orderers orderers; private Peers peers; private Chaincode chaincode; private HFClient client; private FabricOrg fabricOrg; private Channel channel; private ChaincodeID chaincodeID; public ChaincodeManager(String username, FabricConfig fabricConfig) throws CryptoException, InvalidArgumentException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException, TransactionException { this.config = fabricConfig; orderers = this.config.getOrderers(); peers = this.config.getPeers(); chaincode = this.config.getChaincode(); client = HFClient.createNewInstance(); log.debug("Create instance of HFClient"); client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite()); log.debug("Set Crypto Suite of HFClient"); fabricOrg = getFabricOrg(username, config.openCATLS()); channel = getChannel(); chaincodeID = getChaincodeID(); client.setUserContext(fabricOrg.getPeerAdmin()); } private FabricOrg getFabricOrg(String username, boolean openCATLS) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException { // java.io.tmpdir : C:\Users\yangyi47\AppData\Local\Temp\ File storeFile = new File(System.getProperty("java.io.tmpdir") + "/HFCSampletest.properties"); FabricStore fabricStore = new FabricStore(storeFile); // Get Org1 from configuration FabricOrg fabricOrg = new FabricOrg(username, peers, orderers, fabricStore, config.getCryptoConfigPath(), openCATLS); log.debug("Get FabricOrg"); return fabricOrg; } private Channel getChannel() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException, CryptoException, InvalidArgumentException, TransactionException { client.setUserContext(fabricOrg.getPeerAdmin()); return getChannel(fabricOrg, client); } private Channel getChannel(FabricOrg fabricOrg, HFClient client) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException, CryptoException, InvalidArgumentException, TransactionException { Channel channel = client.newChannel(chaincode.getChannelName()); log.debug("Get Chain " + chaincode.getChannelName()); channel.setTransactionWaitTime(chaincode.getTransactionWaitTime()); channel.setDeployWaitTime(chaincode.getDeployWaitTime()); for (int i = 0; i < peers.get().size(); i++) { File peerCert = Paths.get(config.getCryptoConfigPath(), "/peerOrganizations", peers.getOrgDomainName(), "peers", peers.get().get(i).getPeerName(), "tls/server.crt") .toFile(); if (!peerCert.exists()) { throw new RuntimeException( String.format("Missing cert file for: %s. Could not find at location: %s", peers.get().get(i).getPeerName(), peerCert.getAbsolutePath())); } Properties peerProperties = new Properties(); peerProperties.setProperty("pemFile", peerCert.getAbsolutePath()); // ret.setProperty("trustServerCertificate", "true"); //testing // environment only NOT FOR PRODUCTION! peerProperties.setProperty("hostnameOverride", peers.getOrgDomainName()); peerProperties.setProperty("sslProvider", "openSSL"); peerProperties.setProperty("negotiationType", "TLS"); // 在grpc的NettyChannelBuilder上设置特定选项 peerProperties.put("grpc.ManagedChannelBuilderOption.maxInboundMessageSize", 9000000); channel.addPeer(client.newPeer(peers.get().get(i).getPeerName(), fabricOrg.getPeerLocation(peers.get().get(i).getPeerName()), peerProperties)); if (peers.get().get(i).isAddEventHub()) { channel.addEventHub( client.newEventHub(peers.get().get(i).getPeerEventHubName(), fabricOrg.getEventHubLocation(peers.get().get(i).getPeerEventHubName()), peerProperties)); } } for (int i = 0; i < orderers.get().size(); i++) { File ordererCert = Paths.get(config.getCryptoConfigPath(), "/ordererOrganizations", orderers.getOrdererDomainName(), "orderers", orderers.get().get(i).getOrdererName(), "tls/server.crt").toFile(); if (!ordererCert.exists()) { throw new RuntimeException( String.format("Missing cert file for: %s. Could not find at location: %s", orderers.get().get(i).getOrdererName(), ordererCert.getAbsolutePath())); } Properties ordererProperties = new Properties(); ordererProperties.setProperty("pemFile", ordererCert.getAbsolutePath()); ordererProperties.setProperty("hostnameOverride", orderers.getOrdererDomainName()); ordererProperties.setProperty("sslProvider", "openSSL"); ordererProperties.setProperty("negotiationType", "TLS"); ordererProperties.put("grpc.ManagedChannelBuilderOption.maxInboundMessageSize", 9000000); ordererProperties.setProperty("ordererWaitTimeMilliSecs", "300000"); channel.addOrderer( client.newOrderer(orderers.get().get(i).getOrdererName(), fabricOrg.getOrdererLocation(orderers.get().get(i).getOrdererName()), ordererProperties)); } log.debug("channel.isInitialized() = " + channel.isInitialized()); if (!channel.isInitialized()) { channel.initialize(); } if (config.isRegisterEvent()) { log.debug("========================Event事件监听注册========================"); channel.registerBlockListener(new BlockListener() { @Override public void received(BlockEvent event) { // TODO log.debug("========================Event事件监听开始========================"); try { log.debug("event.getChannelId() = " + event.getChannelId()); log.debug("event.getEvent().getChaincodeEvent().getPayload().toStringUtf8() = " + event.getEvent().getChaincodeEvent().getPayload().toStringUtf8()); log.debug("event.getBlock().getData().getDataList().size() = " + event.getBlock().getData().getDataList().size()); ByteString byteString = event.getBlock().getData().getData(0); String result = byteString.toStringUtf8(); log.debug("byteString.toStringUtf8() = " + result); String r1[] = result.split("END CERTIFICATE"); String rr = r1[2]; log.debug("rr = " + rr); } catch (InvalidProtocolBufferException e) { // TODO e.printStackTrace(); } log.debug("========================Event事件监听结束========================"); } }); } return channel; } private ChaincodeID getChaincodeID() { return ChaincodeID.newBuilder().setName(chaincode.getChaincodeName()).setVersion(chaincode.getChaincodeVersion()).setPath(chaincode.getChaincodePath()).build(); } /** * 执行智能合约 * * @param fcn * 方法名 * @param args * 参数数组 * @return * @throws InvalidArgumentException * @throws ProposalException * @throws InterruptedException * @throws ExecutionException * @throws TimeoutException * @throws IOException * @throws TransactionException * @throws CryptoException * @throws InvalidKeySpecException * @throws NoSuchProviderException * @throws NoSuchAlgorithmException */ public Map<String, String> invoke(String fcn, String[] args) throws InvalidArgumentException, ProposalException, InterruptedException, ExecutionException, TimeoutException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CryptoException, TransactionException, IOException { Map<String, String> resultMap = new HashMap<>(); Collection<ProposalResponse> successful = new LinkedList<>(); Collection<ProposalResponse> failed = new LinkedList<>(); /// Send transaction proposal to all peers TransactionProposalRequest transactionProposalRequest = client.newTransactionProposalRequest(); transactionProposalRequest.setChaincodeID(chaincodeID); transactionProposalRequest.setFcn(fcn); transactionProposalRequest.setArgs(args); Map<String, byte[]> tm2 = new HashMap<>(); tm2.put("HyperLedgerFabric", "TransactionProposalRequest:JavaSDK".getBytes(UTF_8)); tm2.put("method", "TransactionProposalRequest".getBytes(UTF_8)); tm2.put("result", ":)".getBytes(UTF_8)); transactionProposalRequest.setTransientMap(tm2); long currentStart = System.currentTimeMillis(); Collection<ProposalResponse> transactionPropResp = channel.sendTransactionProposal(transactionProposalRequest, channel.getPeers()); for (ProposalResponse response : transactionPropResp) { if (response.getStatus() == ProposalResponse.Status.SUCCESS) { successful.add(response); } else { failed.add(response); } } log.info("channel send transaction proposal time = " + ( System.currentTimeMillis() - currentStart)); Collection<Set<ProposalResponse>> proposalConsistencySets = SDKUtils.getProposalConsistencySets(transactionPropResp); if (proposalConsistencySets.size() != 1) { log.error("Expected only one set of consistent proposal responses but got " + proposalConsistencySets.size()); } if (failed.size() > 0) { ProposalResponse firstTransactionProposalResponse = failed.iterator().next(); log.error("Not enough endorsers for inspect:" + failed.size() + " endorser error: " + firstTransactionProposalResponse.getMessage() + ". Was verified: " + firstTransactionProposalResponse.isVerified()); resultMap.put("code", "error"); resultMap.put("data", firstTransactionProposalResponse.getMessage()); return resultMap; } else { log.info("Successfully received transaction proposal responses."); ProposalResponse resp = transactionPropResp.iterator().next(); log.debug("TransactionID: " + resp.getTransactionID()); byte[] x = resp.getChaincodeActionResponsePayload(); String resultAsString = null; if (x != null) { resultAsString = new String(x, "UTF-8"); } log.info("resultAsString = " + resultAsString); channel.sendTransaction(successful); resultMap.put("code", "success"); resultMap.put("data", resultAsString); resultMap.put("txid", resp.getTransactionID()); return resultMap; } // channel.sendTransaction(successful).thenApply(transactionEvent -> { // if (transactionEvent.isValid()) { // log.info("Successfully send transaction proposal to orderer. Transaction ID: " + transactionEvent.getTransactionID()); // } else { // log.info("Failed to send transaction proposal to orderer"); // } // // chain.shutdown(true); // return transactionEvent.getTransactionID(); // }).get(chaincode.getInvokeWatiTime(), TimeUnit.SECONDS); } /** * 查询智能合约 * * @param fcn * 方法名 * @param args * 参数数组 * @return * @throws InvalidArgumentException * @throws ProposalException * @throws IOException * @throws TransactionException * @throws CryptoException * @throws InvalidKeySpecException * @throws NoSuchProviderException * @throws NoSuchAlgorithmException */ public Map<String, String> query(String fcn, String[] args) throws InvalidArgumentException, ProposalException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CryptoException, TransactionException, IOException { Map<String, String> resultMap = new HashMap<>(); String payload = ""; QueryByChaincodeRequest queryByChaincodeRequest = client.newQueryProposalRequest(); queryByChaincodeRequest.setArgs(args); queryByChaincodeRequest.setFcn(fcn); queryByChaincodeRequest.setChaincodeID(chaincodeID); Map<String, byte[]> tm2 = new HashMap<>(); tm2.put("HyperLedgerFabric", "QueryByChaincodeRequest:JavaSDK".getBytes(UTF_8)); tm2.put("method", "QueryByChaincodeRequest".getBytes(UTF_8)); queryByChaincodeRequest.setTransientMap(tm2); Collection<ProposalResponse> queryProposals = channel.queryByChaincode(queryByChaincodeRequest, channel.getPeers()); for (ProposalResponse proposalResponse : queryProposals) { if (!proposalResponse.isVerified() || proposalResponse.getStatus() != ProposalResponse.Status.SUCCESS) { log.debug("Failed query proposal from peer " + proposalResponse.getPeer().getName() + " status: " + proposalResponse.getStatus() + ". Messages: " + proposalResponse.getMessage() + ". Was verified : " + proposalResponse.isVerified()); resultMap.put("code", "error"); resultMap.put("data", "Failed query proposal from peer " + proposalResponse.getPeer().getName() + " status: " + proposalResponse.getStatus() + ". Messages: " + proposalResponse.getMessage() + ". Was verified : " + proposalResponse.isVerified()); } else { payload = proposalResponse.getProposalResponse().getResponse().getPayload().toStringUtf8(); log.debug("Query payload from peer: " + proposalResponse.getPeer().getName()); log.debug("TransactionID: " + proposalResponse.getTransactionID()); log.debug("" + payload); resultMap.put("code", "success"); resultMap.put("data", payload); resultMap.put("txid", proposalResponse.getTransactionID()); } } return resultMap; } public Map<String, String> queryBlockByTransactionID(String txID) throws InvalidArgumentException, ProposalException, CertificateException, IOException { BlockInfo blockInfo = channel.queryBlockByTransactionID(txID); execBlockInfo(blockInfo); return null; } public Map<String, String> queryBlockByHash(byte[] blockHash) throws InvalidArgumentException, ProposalException, IOException { BlockInfo blockInfo = channel.queryBlockByHash(blockHash); execBlockInfo(blockInfo); return null; } public Map<String, String> queryBlockByNumber(long blockNumber) throws InvalidArgumentException, ProposalException, IOException { BlockInfo blockInfo = channel.queryBlockByNumber(blockNumber); execBlockInfo(blockInfo); return null; } private void execBlockInfo(BlockInfo blockInfo) throws InvalidArgumentException, IOException { final long blockNumber = blockInfo.getBlockNumber(); log.debug("blockNumber = " + blockNumber); log.debug("data hash: " + Hex.encodeHexString(blockInfo.getDataHash())); log.debug("previous hash id: " + Hex.encodeHexString(blockInfo.getPreviousHash())); log.debug("calculated block hash is " + Hex.encodeHexString(SDKUtils.calculateBlockHash(blockNumber, blockInfo.getPreviousHash(), blockInfo.getDataHash()))); final int envelopeCount = blockInfo.getEnvelopeCount(); log.debug("block number " + blockNumber + " has " + envelopeCount + " envelope count:"); for(EnvelopeInfo info: blockInfo.getEnvelopeInfos()) { final String channelId = info.getChannelId(); log.debug("ChannelId = " + channelId); log.debug("Epoch = " + info.getEpoch()); log.debug("TransactionID = " + info.getTransactionID()); log.debug("ValidationCode = " + info.getValidationCode()); log.debug("Timestamp = " + DateUtil.obtain().parseDateFormat(new Date(info.getTimestamp().getTime()), "yyyy年MM月dd日 HH时mm分ss秒")); log.debug("Type = " + info.getType()); if (info.getType() == EnvelopeType.TRANSACTION_ENVELOPE) { BlockInfo.TransactionEnvelopeInfo txeInfo = (TransactionEnvelopeInfo) info; int txCount = txeInfo.getTransactionActionInfoCount(); log.debug("Transaction number " + blockNumber + " has actions count = " + txCount); log.debug("Transaction number " + blockNumber + " isValid = " + txeInfo.isValid()); log.debug("Transaction number " + blockNumber + " validation code = " + txeInfo.getValidationCode()); for (int i = 0; i < txCount; i++) { BlockInfo.TransactionEnvelopeInfo.TransactionActionInfo txInfo = txeInfo.getTransactionActionInfo(i); log.debug("Transaction action " + i + " has response status " + txInfo.getResponseStatus()); log.debug("Transaction action " + i + " has response message bytes as string: " + printableString(new String(txInfo.getResponseMessageBytes(), "UTF-8"))); log.debug("Transaction action " + i + " has endorsements " + txInfo.getEndorsementsCount()); for (int n = 0; n < txInfo.getEndorsementsCount(); ++n) { BlockInfo.EndorserInfo endorserInfo = txInfo.getEndorsementInfo(n); log.debug("Endorser " + n + " signature: " + Hex.encodeHexString(endorserInfo.getSignature())); log.debug("Endorser " + n + " endorser: " + new String(endorserInfo.getEndorser(), "UTF-8")); } log.debug("Transaction action " + i + " has " + txInfo.getChaincodeInputArgsCount() + " chaincode input arguments"); for (int z = 0; z < txInfo.getChaincodeInputArgsCount(); ++z) { log.debug("Transaction action " + i + " has chaincode input argument " + z + "is: " + printableString(new String(txInfo.getChaincodeInputArgs(z), "UTF-8"))); } log.debug("Transaction action " + i + " proposal response status: " + txInfo.getProposalResponseStatus()); log.debug("Transaction action " + i + " proposal response payload: " + printableString(new String(txInfo.getProposalResponsePayload()))); TxReadWriteSetInfo rwsetInfo = txInfo.getTxReadWriteSet(); if (null != rwsetInfo) { log.debug("Transaction action " + i + " has " + rwsetInfo.getNsRwsetCount() +" name space read write sets"); for (TxReadWriteSetInfo.NsRwsetInfo nsRwsetInfo : rwsetInfo.getNsRwsetInfos()) { final String namespace = nsRwsetInfo.getNamespace(); KvRwset.KVRWSet rws = nsRwsetInfo.getRwset(); int rs = -1; for (KvRwset.KVRead readList : rws.getReadsList()) { rs++; log.debug("Namespace " + namespace + " read set " + rs + " key " + readList.getKey() + " version [" + readList.getVersion().getBlockNum() + " : " + readList.getVersion().getTxNum() + "]"); } rs = -1; for (KvRwset.KVWrite writeList : rws.getWritesList()) { rs++; String valAsString = printableString(new String(writeList.getValue().toByteArray(), "UTF-8")); log.debug("Namespace " + namespace + " write set " + rs + " key " + writeList.getKey() + " has value " + valAsString); } } } } } } } static String printableString(final String string) { int maxLogStringLength = 64; if (string == null || string.length() == 0) { return string; } String ret = string.replaceAll("[^\\p{Print}]", "?"); ret = ret.substring(0, Math.min(ret.length(), maxLogStringLength)) + (ret.length() > maxLogStringLength ? "..." : ""); return ret; } }