Hyperledger Fabric 1.0 從零開始(十)——智能合約(參閱:Hyperledger Fabric Chaincode for Operators——實操智能合約)html
Hyperledger Fabric 1.0 從零開始(十一)——CouchDB(參閱:Hyperledger Fabric CouchDB as the State Database——使用CouchDB)java
上述兩章,最近網上各路大神文章雲集,方案多多,由於最近工做太忙太忙,我暫時就先不贅述了,能夠優先參考深藍大大的文章HyperLedger Fabric ChainCode開發——shim.ChaincodeStubInterface用法。git
這章先撿你們都比較在乎的java sdk應用方案貼出來,不少朋友都找我要過,我主要是把註釋都寫進去了,用法簡單了說了下,通常狀況下會java開發的都能看懂。github
年前實在太忙。web
官方在Fabric1.0以後就推薦使用SDK來實現交互的操做,本來在0.6上的restapi已經被廢棄。JAVA-SDK能夠參考github。官方給的SDK的DEMO很難入手,註釋稀少內容還很雜,所幸感謝github上有位朋友(具體地址實在是找不到了,之後會補上)稍加整理了一下,直接重寫了官方的DEMO,讓像我這樣的新人更容易入手。apache
本次在官方SDK和大神從新的DEMO的基礎上作了一次整理,可以更加清晰簡單的入門並使用JAVA-SDK來進行交互。api
相信看到這裏的朋友應該都對Fabric已經有了足夠的瞭解,至少是應用層上已經能夠實現分佈式帳本的各項功能,sdk也是在這樣的基礎進行講述。數組
首先看下針對JAVA-SDK所寫的輔助工程目錄緩存
關於Fabric,咱們知道一個channel中能夠建立多個chaincode,而一個chaincode須要指定對應orderer和peer。tomcat
因此,在此創建了一個bean目錄來存放自定義的chaincode、orderer和peer對象。這幾個對象都包含各自最基本的訪問屬性。
具體對應關係以下:
bean.Chaincode - Fabric建立的chaincode信息,涵蓋所屬channel等信息
bean.Orderers - Fabric建立的orderer信息,涵蓋單機和集羣兩種方案
bean.Peers - Fabric建立的peer信息,包含有cli、org、ca、couchdb等節點服務器關聯啓動服務信息集合
ChaincodeManager - 智能合約操做總控制器
FabricConfig - 智能合約操做總參數配置器
FabricOrg - 聯盟組織對象
FabricUser - 聯盟用戶對象
FabricStore - 聯盟存儲配置對象
直接經過代碼來看實現
1 package cn.aberic.fabric.bean; 2 3 /** 4 * Fabric建立的chaincode信息,涵蓋所屬channel等信息 5 * 6 * @author aberic 7 * 8 * @date 2017年10月18日 - 下午2:07:42 9 * @email abericyang@gmail.com 10 */ 11 public class Chaincode { 12 13 /** 當前將要訪問的智能合約所屬頻道名稱 */ 14 private String channelName; // ffetest 15 /** 智能合約名稱 */ 16 private String chaincodeName; // ffetestcc 17 /** 智能合約安裝路徑 */ 18 private String chaincodePath; // github.com/hyperledger/fabric/xxx/chaincode/go/example/test 19 /** 智能合約版本號 */ 20 private String chaincodeVersion; // 1.0 21 /** 執行智能合約操做等待時間 */ 22 private int invokeWatiTime = 100000; 23 /** 執行智能合約實例等待時間 */ 24 private int deployWatiTime = 120000; 25 26 public String getChannelName() { 27 return channelName; 28 } 29 30 public void setChannelName(String channelName) { 31 this.channelName = channelName; 32 } 33 34 public String getChaincodeName() { 35 return chaincodeName; 36 } 37 38 public void setChaincodeName(String chaincodeName) { 39 this.chaincodeName = chaincodeName; 40 } 41 42 public String getChaincodePath() { 43 return chaincodePath; 44 } 45 46 public void setChaincodePath(String chaincodePath) { 47 this.chaincodePath = chaincodePath; 48 } 49 50 public String getChaincodeVersion() { 51 return chaincodeVersion; 52 } 53 54 public void setChaincodeVersion(String chaincodeVersion) { 55 this.chaincodeVersion = chaincodeVersion; 56 } 57 58 public int getInvokeWatiTime() { 59 return invokeWatiTime; 60 } 61 62 public void setInvokeWatiTime(int invokeWatiTime) { 63 this.invokeWatiTime = invokeWatiTime; 64 } 65 66 public int getDeployWatiTime() { 67 return deployWatiTime; 68 } 69 70 public void setDeployWatiTime(int deployWatiTime) { 71 this.deployWatiTime = deployWatiTime; 72 } 73 74 }
1 package cn.aberic.fabric.bean; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * Fabric建立的orderer信息,涵蓋單機和集羣兩種方案 8 * 9 * @author aberic 10 * 11 * @date 2017年10月18日 - 下午1:56:48 12 * @email abericyang@gmail.com 13 */ 14 public class Orderers { 15 16 /** orderer 排序服務器所在根域名 */ 17 private String ordererDomainName; // anti-moth.com 18 /** orderer 排序服務器集合 */ 19 private List<Orderer> orderers; 20 21 public Orderers() { 22 orderers = new ArrayList<>(); 23 } 24 25 public String getOrdererDomainName() { 26 return ordererDomainName; 27 } 28 29 public void setOrdererDomainName(String ordererDomainName) { 30 this.ordererDomainName = ordererDomainName; 31 } 32 33 /** 新增排序服務器 */ 34 public void addOrderer(String name, String location) { 35 orderers.add(new Orderer(name, location)); 36 } 37 38 /** 獲取排序服務器集合 */ 39 public List<Orderer> get() { 40 return orderers; 41 } 42 43 /** 44 * 排序服務器對象 45 * 46 * @author aberic 47 * 48 * @date 2017年10月18日 - 下午2:06:22 49 * @email abericyang@gmail.com 50 */ 51 public class Orderer { 52 53 /** orderer 排序服務器的域名 */ 54 private String ordererName; 55 /** orderer 排序服務器的訪問地址 */ 56 private String ordererLocation; 57 58 public Orderer(String ordererName, String ordererLocation) { 59 super(); 60 this.ordererName = ordererName; 61 this.ordererLocation = ordererLocation; 62 } 63 64 public String getOrdererName() { 65 return ordererName; 66 } 67 68 public void setOrdererName(String ordererName) { 69 this.ordererName = ordererName; 70 } 71 72 public String getOrdererLocation() { 73 return ordererLocation; 74 } 75 76 public void setOrdererLocation(String ordererLocation) { 77 this.ordererLocation = ordererLocation; 78 } 79 80 } 81 82 }
1 package cn.aberic.fabric.bean; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * Fabric建立的peer信息,包含有cli、org、ca、couchdb等節點服務器關聯啓動服務信息集合 8 * 9 * @author aberic 10 * 11 * @date 2017年10月18日 - 下午1:49:03 12 * @email abericyang@gmail.com 13 */ 14 public class Peers { 15 16 /** 當前指定的組織名稱 */ 17 private String orgName; // Org1 18 /** 當前指定的組織名稱 */ 19 private String orgMSPID; // Org1MSP 20 /** 當前指定的組織所在根域名 */ 21 private String orgDomainName; //org1.example.com 22 /** orderer 排序服務器集合 */ 23 private List<Peer> peers; 24 25 public Peers() { 26 peers = new ArrayList<>(); 27 } 28 29 public String getOrgName() { 30 return orgName; 31 } 32 33 public void setOrgName(String orgName) { 34 this.orgName = orgName; 35 } 36 37 public String getOrgMSPID() { 38 return orgMSPID; 39 } 40 41 public void setOrgMSPID(String orgMSPID) { 42 this.orgMSPID = orgMSPID; 43 } 44 45 public String getOrgDomainName() { 46 return orgDomainName; 47 } 48 49 public void setOrgDomainName(String orgDomainName) { 50 this.orgDomainName = orgDomainName; 51 } 52 53 /** 新增排序服務器 */ 54 public void addPeer(String peerName, String peerEventHubName, String peerLocation, String peerEventHubLocation, String caLocation) { 55 peers.add(new Peer(peerName, peerEventHubName, peerLocation, peerEventHubLocation, caLocation)); 56 } 57 58 /** 獲取排序服務器集合 */ 59 public List<Peer> get() { 60 return peers; 61 } 62 63 /** 64 * 節點服務器對象 65 * 66 * @author aberic 67 * 68 * @date 2017年11月11日 - 下午6:56:14 69 * @email abericyang@gmail.com 70 */ 71 public class Peer { 72 73 /** 當前指定的組織節點域名 */ 74 private String peerName; // peer0.org1.example.com 75 /** 當前指定的組織節點事件域名 */ 76 private String peerEventHubName; // peer0.org1.example.com 77 /** 當前指定的組織節點訪問地址 */ 78 private String peerLocation; // grpc://110.131.116.21:7051 79 /** 當前指定的組織節點事件監聽訪問地址 */ 80 private String peerEventHubLocation; // grpc://110.131.116.21:7053 81 /** 當前指定的組織節點ca訪問地址 */ 82 private String caLocation; // http://110.131.116.21:7054 83 /** 當前peer是否增長Event事件處理 */ 84 private boolean addEventHub = false; 85 86 public Peer(String peerName, String peerEventHubName, String peerLocation, String peerEventHubLocation, String caLocation) { 87 this.peerName = peerName; 88 this.peerEventHubName = peerEventHubName; 89 this.peerLocation = peerLocation; 90 this.peerEventHubLocation = peerEventHubLocation; 91 this.caLocation = caLocation; 92 } 93 94 public String getPeerName() { 95 return peerName; 96 } 97 98 public void setPeerName(String peerName) { 99 this.peerName = peerName; 100 } 101 102 public String getPeerEventHubName() { 103 return peerEventHubName; 104 } 105 106 public void setPeerEventHubName(String peerEventHubName) { 107 this.peerEventHubName = peerEventHubName; 108 } 109 110 public String getPeerLocation() { 111 return peerLocation; 112 } 113 114 public void setPeerLocation(String peerLocation) { 115 this.peerLocation = peerLocation; 116 } 117 118 public String getPeerEventHubLocation() { 119 return peerEventHubLocation; 120 } 121 122 public void setPeerEventHubLocation(String eventHubLocation) { 123 this.peerEventHubLocation = eventHubLocation; 124 } 125 126 public String getCaLocation() { 127 return caLocation; 128 } 129 130 public void setCaLocation(String caLocation) { 131 this.caLocation = caLocation; 132 } 133 134 public boolean isAddEventHub() { 135 return addEventHub; 136 } 137 138 public void addEventHub(boolean addEventHub) { 139 this.addEventHub = addEventHub; 140 } 141 142 } 143 144 }
1 package cn.aberic.fabric; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.io.ObjectInputStream; 7 import java.io.ObjectOutputStream; 8 import java.io.Serializable; 9 import java.util.Set; 10 11 import org.bouncycastle.util.encoders.Hex; 12 import org.hyperledger.fabric.sdk.Enrollment; 13 import org.hyperledger.fabric.sdk.User; 14 15 import io.netty.util.internal.StringUtil; 16 17 /** 18 * 聯盟用戶對象 19 * 20 * @author aberic 21 * 22 * @date 2017年9月7日 - 下午4:36:53 23 * @email abericyang@gmail.com 24 */ 25 class FabricUser implements User, Serializable { 26 27 private static final long serialVersionUID = 5695080465408336815L; 28 29 /** 名稱 */ 30 private String name; 31 /** 規則 */ 32 private Set<String> roles; 33 /** 帳戶 */ 34 private String account; 35 /** 從屬聯盟 */ 36 private String affiliation; 37 /** 組織 */ 38 private String organization; 39 /** 註冊操做的密�? */ 40 private String enrollmentSecret; 41 /** 會員id */ 42 private String mspId; 43 /** 註冊登記操做 */ 44 Enrollment enrollment = null; // �?要在測試env中訪�? 45 46 /** 存儲配置對象 */ 47 private transient FabricStore keyValStore; 48 private String keyValStoreName; 49 50 public FabricUser(String name, String org, FabricStore store) { 51 this.name = name; 52 this.keyValStore = store; 53 this.organization = org; 54 this.keyValStoreName = toKeyValStoreName(this.name, org); 55 56 String memberStr = keyValStore.getValue(keyValStoreName); 57 if (null != memberStr) { 58 saveState(); 59 } else { 60 restoreState(); 61 } 62 } 63 64 /** 65 * 設置帳戶信息並將用戶狀�?�更新至存儲配置對象 66 * 67 * @param account 68 * 帳戶 69 */ 70 public void setAccount(String account) { 71 this.account = account; 72 saveState(); 73 } 74 75 @Override 76 public String getAccount() { 77 return this.account; 78 } 79 80 /** 81 * 設置從屬聯盟信息並將用戶狀�?�更新至存儲配置對象 82 * 83 * @param affiliation 84 * 從屬聯盟 85 */ 86 public void setAffiliation(String affiliation) { 87 this.affiliation = affiliation; 88 saveState(); 89 } 90 91 @Override 92 public String getAffiliation() { 93 return this.affiliation; 94 } 95 96 @Override 97 public Enrollment getEnrollment() { 98 return this.enrollment; 99 } 100 101 /** 102 * 設置會員id信息並將用戶狀�?�更新至存儲配置對象 103 * 104 * @param mspID 105 * 會員id 106 */ 107 public void setMspId(String mspID) { 108 this.mspId = mspID; 109 saveState(); 110 } 111 112 @Override 113 public String getMspId() { 114 return this.mspId; 115 } 116 117 @Override 118 public String getName() { 119 return this.name; 120 } 121 122 /** 123 * 設置規則信息並將用戶狀�?�更新至存儲配置對象 124 * 125 * @param roles 126 * 規則 127 */ 128 public void setRoles(Set<String> roles) { 129 this.roles = roles; 130 saveState(); 131 } 132 133 @Override 134 public Set<String> getRoles() { 135 return this.roles; 136 } 137 138 public String getEnrollmentSecret() { 139 return enrollmentSecret; 140 } 141 142 /** 143 * 設置註冊操做的密鑰信息並將用戶狀態更新至存儲配置對象 144 * 145 * @param enrollmentSecret 146 * 註冊操做的密�? 147 */ 148 public void setEnrollmentSecret(String enrollmentSecret) { 149 this.enrollmentSecret = enrollmentSecret; 150 saveState(); 151 } 152 153 /** 154 * 設置註冊登記操做信息並將用戶狀�?�更新至存儲配置對象 155 * 156 * @param enrollment 157 * 註冊登記操做 158 */ 159 public void setEnrollment(Enrollment enrollment) { 160 this.enrollment = enrollment; 161 saveState(); 162 } 163 164 /** 165 * 肯定這個名稱是否已注�? 166 * 167 * @return 與否 168 */ 169 public boolean isRegistered() { 170 return !StringUtil.isNullOrEmpty(enrollmentSecret); 171 } 172 173 /** 174 * 肯定這個名字是否已經註冊 175 * 176 * @return 與否 177 */ 178 public boolean isEnrolled() { 179 return this.enrollment != null; 180 } 181 182 /** 將用戶狀態保存至存儲配置對象 */ 183 public void saveState() { 184 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 185 try { 186 ObjectOutputStream oos = new ObjectOutputStream(bos); 187 oos.writeObject(this); 188 oos.flush(); 189 keyValStore.setValue(keyValStoreName, Hex.toHexString(bos.toByteArray())); 190 bos.close(); 191 } catch (IOException e) { 192 e.printStackTrace(); 193 } 194 } 195 196 /** 197 * 從鍵值存儲中恢復該用戶的狀�??(若是找到的話)。若是找不到,什麼也不要作�?? 198 * 199 * @return 返回用戶 200 */ 201 private FabricUser restoreState() { 202 String memberStr = keyValStore.getValue(keyValStoreName); 203 if (null != memberStr) { 204 // 用戶在鍵值存儲中被找到,所以恢復狀�?��?? 205 byte[] serialized = Hex.decode(memberStr); 206 ByteArrayInputStream bis = new ByteArrayInputStream(serialized); 207 try { 208 ObjectInputStream ois = new ObjectInputStream(bis); 209 FabricUser state = (FabricUser) ois.readObject(); 210 if (state != null) { 211 this.name = state.name; 212 this.roles = state.roles; 213 this.account = state.account; 214 this.affiliation = state.affiliation; 215 this.organization = state.organization; 216 this.enrollmentSecret = state.enrollmentSecret; 217 this.enrollment = state.enrollment; 218 this.mspId = state.mspId; 219 return this; 220 } 221 } catch (Exception e) { 222 throw new RuntimeException(String.format("Could not restore state of member %s", this.name), e); 223 } 224 } 225 return null; 226 } 227 228 public static String toKeyValStoreName(String name, String org) { 229 System.out.println("toKeyValStoreName = " + "user." + name + org); 230 return "user." + name + org; 231 } 232 233 }
1 package cn.aberic.fabric; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.nio.file.Paths; 6 import java.security.NoSuchAlgorithmException; 7 import java.security.NoSuchProviderException; 8 import java.security.spec.InvalidKeySpecException; 9 import java.util.Collection; 10 import java.util.Collections; 11 import java.util.HashMap; 12 import java.util.HashSet; 13 import java.util.Map; 14 import java.util.Properties; 15 import java.util.Set; 16 17 import org.apache.log4j.Logger; 18 import org.hyperledger.fabric.sdk.Peer; 19 import org.hyperledger.fabric.sdk.User; 20 import org.hyperledger.fabric_ca.sdk.HFCAClient; 21 22 import cn.aberic.fabric.bean.Orderers; 23 24 /** 25 * 聯盟組織對象 26 * 27 * @author aberic 28 * 29 * @date 2017年9月7日 - 下午4:35:40 30 * @email abericyang@gmail.com 31 */ 32 class FabricOrg { 33 34 private static Logger log = Logger.getLogger(FabricOrg.class); 35 36 /** 名稱 */ 37 private String name; 38 /** 會員id */ 39 private String mspid; 40 /** ca 客戶端 */ 41 private HFCAClient caClient; 42 43 /** 用戶集合 */ 44 Map<String, User> userMap = new HashMap<>(); 45 /** 本地節點集合 */ 46 Map<String, String> peerLocations = new HashMap<>(); 47 /** 本地排序服務集合 */ 48 Map<String, String> ordererLocations = new HashMap<>(); 49 /** 本地事件集合 */ 50 Map<String, String> eventHubLocations = new HashMap<>(); 51 /** 節點集合 */ 52 Set<Peer> peers = new HashSet<>(); 53 /** 聯盟管理員用戶 */ 54 private FabricUser admin; 55 /** 本地 ca */ 56 private String caLocation; 57 /** ca 配置 */ 58 private Properties caProperties = null; 59 60 /** 聯盟單節點管理員用戶 */ 61 private FabricUser peerAdmin; 62 63 /** 域名名稱 */ 64 private String domainName; 65 66 public FabricOrg(cn.aberic.fabric.bean.Peers peers, Orderers orderers, FabricStore fabricStore, String cryptoConfigPath) 67 throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException { 68 this.name = peers.getOrgName(); 69 this.mspid = peers.getOrgMSPID(); 70 for (int i = 0; i < peers.get().size(); i++) { 71 addPeerLocation(peers.get().get(i).getPeerName(), peers.get().get(i).getPeerLocation()); 72 addEventHubLocation(peers.get().get(i).getPeerEventHubName(), peers.get().get(i).getPeerEventHubLocation()); 73 setCALocation(peers.get().get(i).getCaLocation()); 74 } 75 for (int i = 0; i < orderers.get().size(); i++) { 76 addOrdererLocation(orderers.get().get(i).getOrdererName(), orderers.get().get(i).getOrdererLocation()); 77 } 78 setDomainName(peers.getOrgDomainName()); // domainName=tk.anti-moth.com 79 80 // Set up HFCA for Org1 81 // setCAClient(HFCAClient.createNewInstance(peers.getCaLocation(), getCAProperties())); 82 83 setAdmin(fabricStore.getMember("admin", peers.getOrgName())); // 設置該組織的管理員 84 85 File skFile = Paths.get(cryptoConfigPath, "/peerOrganizations/", peers.getOrgDomainName(), String.format("/users/Admin@%s/msp/keystore", peers.getOrgDomainName())).toFile(); 86 File certificateFile = Paths.get(cryptoConfigPath, "/peerOrganizations/", peers.getOrgDomainName(), 87 String.format("/users/Admin@%s/msp/signcerts/Admin@%s-cert.pem", peers.getOrgDomainName(), peers.getOrgDomainName())).toFile(); 88 log.debug("skFile = " + skFile.getAbsolutePath()); 89 log.debug("certificateFile = " + certificateFile.getAbsolutePath()); 90 setPeerAdmin(fabricStore.getMember(peers.getOrgName() + "Admin", peers.getOrgName(), peers.getOrgMSPID(), findFileSk(skFile), certificateFile)); // 一個特殊的用戶,能夠建立通道,鏈接對等點,並安裝鏈碼 91 } 92 93 public String getName() { 94 return name; 95 } 96 97 /** 98 * 獲取聯盟管理員用戶 99 * 100 * @return 聯盟管理員用戶 101 */ 102 public FabricUser getAdmin() { 103 return admin; 104 } 105 106 /** 107 * 設置聯盟管理員用戶 108 * 109 * @param admin 110 * 聯盟管理員用戶 111 */ 112 public void setAdmin(FabricUser admin) { 113 this.admin = admin; 114 } 115 116 /** 117 * 獲取會員id 118 * 119 * @return 會員id 120 */ 121 public String getMSPID() { 122 return mspid; 123 } 124 125 /** 126 * 設置本地ca 127 * 128 * @param caLocation 129 * 本地ca 130 */ 131 public void setCALocation(String caLocation) { 132 this.caLocation = caLocation; 133 } 134 135 /** 136 * 獲取本地ca 137 * 138 * @return 本地ca 139 */ 140 public String getCALocation() { 141 return this.caLocation; 142 } 143 144 /** 145 * 添加本地節點 146 * 147 * @param name 148 * 節點key 149 * @param location 150 * 節點 151 */ 152 public void addPeerLocation(String name, String location) { 153 peerLocations.put(name, location); 154 } 155 156 /** 157 * 添加本地組織 158 * 159 * @param name 160 * 組織key 161 * @param location 162 * 組織 163 */ 164 public void addOrdererLocation(String name, String location) { 165 ordererLocations.put(name, location); 166 } 167 168 /** 169 * 添加本地事件 170 * 171 * @param name 172 * 事件key 173 * @param location 174 * 事件 175 */ 176 public void addEventHubLocation(String name, String location) { 177 eventHubLocations.put(name, location); 178 } 179 180 /** 181 * 獲取本地節點 182 * 183 * @param name 184 * 節點key 185 * @return 節點 186 */ 187 public String getPeerLocation(String name) { 188 return peerLocations.get(name); 189 } 190 191 /** 192 * 獲取本地組織 193 * 194 * @param name 195 * 組織key 196 * @return 組織 197 */ 198 public String getOrdererLocation(String name) { 199 return ordererLocations.get(name); 200 } 201 202 /** 203 * 獲取本地事件 204 * 205 * @param name 206 * 事件key 207 * @return 事件 208 */ 209 public String getEventHubLocation(String name) { 210 return eventHubLocations.get(name); 211 } 212 213 /** 214 * 獲取一個不可修改的本地節點key集合 215 * 216 * @return 節點key集合 217 */ 218 public Set<String> getPeerNames() { 219 return Collections.unmodifiableSet(peerLocations.keySet()); 220 } 221 222 /** 223 * 獲取一個不可修改的本地節點集合 224 * 225 * @return 節點集合 226 */ 227 public Set<Peer> getPeers() { 228 return Collections.unmodifiableSet(peers); 229 } 230 231 /** 232 * 獲取一個不可修改的本地組織key集合 233 * 234 * @return 組織key集合 235 */ 236 public Set<String> getOrdererNames() { 237 return Collections.unmodifiableSet(ordererLocations.keySet()); 238 } 239 240 /** 241 * 獲取一個不可修改的本地組織集合 242 * 243 * @return 組織集合 244 */ 245 public Collection<String> getOrdererLocations() { 246 return Collections.unmodifiableCollection(ordererLocations.values()); 247 } 248 249 /** 250 * 獲取一個不可修改的本地事件key集合 251 * 252 * @return 事件key集合 253 */ 254 public Set<String> getEventHubNames() { 255 return Collections.unmodifiableSet(eventHubLocations.keySet()); 256 } 257 258 /** 259 * 獲取一個不可修改的本地事件集合 260 * 261 * @return 事件集合 262 */ 263 public Collection<String> getEventHubLocations() { 264 return Collections.unmodifiableCollection(eventHubLocations.values()); 265 } 266 267 /** 268 * 設置 ca 客戶端 269 * 270 * @param caClient 271 * ca 客戶端 272 */ 273 public void setCAClient(HFCAClient caClient) { 274 this.caClient = caClient; 275 } 276 277 /** 278 * 獲取 ca 客戶端 279 * 280 * @return ca 客戶端 281 */ 282 public HFCAClient getCAClient() { 283 return caClient; 284 } 285 286 /** 287 * 向用戶集合中添加用戶 288 * 289 * @param user 290 * 用戶 291 */ 292 public void addUser(FabricUser user) { 293 userMap.put(user.getName(), user); 294 } 295 296 /** 297 * 從用戶集合根據名稱獲取用戶 298 * 299 * @param name 300 * 名稱 301 * @return 用戶 302 */ 303 public User getUser(String name) { 304 return userMap.get(name); 305 } 306 307 /** 308 * 向節點集合中添加節點 309 * 310 * @param peer 311 * 節點 312 */ 313 public void addPeer(Peer peer) { 314 peers.add(peer); 315 } 316 317 /** 318 * 設置 ca 配置 319 * 320 * @param caProperties 321 * ca 配置 322 */ 323 public void setCAProperties(Properties caProperties) { 324 this.caProperties = caProperties; 325 } 326 327 /** 328 * 獲取 ca 配置 329 * 330 * @return ca 配置 331 */ 332 public Properties getCAProperties() { 333 return caProperties; 334 } 335 336 /** 337 * 設置聯盟單節點管理員用戶 338 * 339 * @param peerAdmin 340 * 聯盟單節點管理員用戶 341 */ 342 public void setPeerAdmin(FabricUser peerAdmin) { 343 this.peerAdmin = peerAdmin; 344 } 345 346 /** 347 * 獲取聯盟單節點管理員用戶 348 * 349 * @return 聯盟單節點管理員用戶 350 */ 351 public FabricUser getPeerAdmin() { 352 return peerAdmin; 353 } 354 355 /** 356 * 設置域名名稱 357 * 358 * @param doainName 359 * 域名名稱 360 */ 361 public void setDomainName(String domainName) { 362 this.domainName = domainName; 363 } 364 365 /** 366 * 獲取域名名稱 367 * 368 * @return 域名名稱 369 */ 370 public String getDomainName() { 371 return domainName; 372 } 373 374 /** 375 * 從指定路徑中獲取後綴爲 _sk 的文件,且該路徑下有且僅有該文件 376 * 377 * @param directorys 378 * 指定路徑 379 * @return File 380 */ 381 private File findFileSk(File directory) { 382 File[] matches = directory.listFiles((dir, name) -> name.endsWith("_sk")); 383 if (null == matches) { 384 throw new RuntimeException(String.format("Matches returned null does %s directory exist?", directory.getAbsoluteFile().getName())); 385 } 386 if (matches.length != 1) { 387 throw new RuntimeException(String.format("Expected in %s only 1 sk file but found %d", directory.getAbsoluteFile().getName(), matches.length)); 388 } 389 return matches[0]; 390 } 391 392 }
1 package cn.aberic.fabric; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.InputStream; 9 import java.io.OutputStream; 10 import java.io.Reader; 11 import java.io.Serializable; 12 import java.io.StringReader; 13 import java.security.NoSuchAlgorithmException; 14 import java.security.NoSuchProviderException; 15 import java.security.PrivateKey; 16 import java.security.Security; 17 import java.security.spec.InvalidKeySpecException; 18 import java.util.HashMap; 19 import java.util.Map; 20 import java.util.Properties; 21 22 import org.apache.commons.io.IOUtils; 23 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 24 import org.bouncycastle.jce.provider.BouncyCastleProvider; 25 import org.bouncycastle.openssl.PEMParser; 26 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; 27 import org.hyperledger.fabric.sdk.Enrollment; 28 29 /** 30 * 聯盟存儲配置對象 31 * 32 * @author aberic 33 * 34 * @date 2017年9月7日 - 下午4:36:19 35 * @email abericyang@gmail.com 36 */ 37 class FabricStore { 38 39 private String file; 40 /** 用戶信息集合 */ 41 private final Map<String, FabricUser> members = new HashMap<>(); 42 43 public FabricStore(File file) { 44 this.file = file.getAbsolutePath(); 45 } 46 47 /** 48 * 設置與名稱相關的值 49 * 50 * @param name 51 * 名稱 52 * @param value 53 * 相關值 54 */ 55 public void setValue(String name, String value) { 56 Properties properties = loadProperties(); 57 try (OutputStream output = new FileOutputStream(file)) { 58 properties.setProperty(name, value); 59 properties.store(output, ""); 60 output.close(); 61 } catch (IOException e) { 62 System.out.println(String.format("Could not save the keyvalue store, reason:%s", e.getMessage())); 63 } 64 } 65 66 /** 67 * 獲取與名稱相關的值 68 * 69 * @param 名稱 70 * @return 相關值 71 */ 72 public String getValue(String name) { 73 Properties properties = loadProperties(); 74 return properties.getProperty(name); 75 } 76 77 /** 78 * 加載配置文件 79 * 80 * @return 配置文件對象 81 */ 82 private Properties loadProperties() { 83 Properties properties = new Properties(); 84 try (InputStream input = new FileInputStream(file)) { 85 properties.load(input); 86 input.close(); 87 } catch (FileNotFoundException e) { 88 System.out.println(String.format("Could not find the file \"%s\"", file)); 89 } catch (IOException e) { 90 System.out.println(String.format("Could not load keyvalue store from file \"%s\", reason:%s", file, e.getMessage())); 91 } 92 return properties; 93 } 94 95 /** 96 * 用給定的名稱獲取用戶 97 * 98 * @param 名稱 99 * @param 組織 100 * 101 * @return 用戶 102 */ 103 public FabricUser getMember(String name, String org) { 104 // 嘗試從緩存中獲取User狀�?? 105 FabricUser fabricUser = members.get(FabricUser.toKeyValStoreName(name, org)); 106 if (null != fabricUser) { 107 return fabricUser; 108 } 109 // 建立User,並嘗試從鍵值存儲中恢復它的狀�??(若是找到的話)�? 110 fabricUser = new FabricUser(name, org, this); 111 return fabricUser; 112 } 113 114 /** 115 * 用給定的名稱獲取用戶 116 * 117 * @param name 118 * 名稱 119 * @param org 120 * 組織 121 * @param mspId 122 * 會員id 123 * @param privateKeyFile 124 * @param certificateFile 125 * 126 * @return user 用戶 127 * 128 * @throws IOException 129 * @throws NoSuchAlgorithmException 130 * @throws NoSuchProviderException 131 * @throws InvalidKeySpecException 132 */ 133 public FabricUser getMember(String name, String org, String mspId, File privateKeyFile, File certificateFile) 134 throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { 135 try { 136 // 嘗試從緩存中獲取User狀�?? 137 FabricUser fabricUser = members.get(FabricUser.toKeyValStoreName(name, org)); 138 if (null != fabricUser) { 139 System.out.println("嘗試從緩存中獲取User狀�?? User = " + fabricUser); 140 return fabricUser; 141 } 142 // 建立User,並嘗試從鍵值存儲中恢復它的狀�??(若是找到的話)�? 143 fabricUser = new FabricUser(name, org, this); 144 fabricUser.setMspId(mspId); 145 String certificate = new String(IOUtils.toByteArray(new FileInputStream(certificateFile)), "UTF-8"); 146 PrivateKey privateKey = getPrivateKeyFromBytes(IOUtils.toByteArray(new FileInputStream(privateKeyFile))); 147 fabricUser.setEnrollment(new StoreEnrollement(privateKey, certificate)); 148 return fabricUser; 149 } catch (IOException e) { 150 e.printStackTrace(); 151 throw e; 152 } catch (NoSuchAlgorithmException e) { 153 e.printStackTrace(); 154 throw e; 155 } catch (NoSuchProviderException e) { 156 e.printStackTrace(); 157 throw e; 158 } catch (InvalidKeySpecException e) { 159 e.printStackTrace(); 160 throw e; 161 } catch (ClassCastException e) { 162 e.printStackTrace(); 163 throw e; 164 } 165 } 166 167 /** 168 * 經過字節數組信息獲取私鑰 169 * 170 * @param data 171 * 字節數組 172 * 173 * @return 私鑰 174 * 175 * @throws IOException 176 * @throws NoSuchProviderException 177 * @throws NoSuchAlgorithmException 178 * @throws InvalidKeySpecException 179 */ 180 private PrivateKey getPrivateKeyFromBytes(byte[] data) throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException { 181 final Reader pemReader = new StringReader(new String(data)); 182 final PrivateKeyInfo pemPair; 183 try (PEMParser pemParser = new PEMParser(pemReader)) { 184 pemPair = (PrivateKeyInfo) pemParser.readObject(); 185 } 186 PrivateKey privateKey = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getPrivateKey(pemPair); 187 return privateKey; 188 } 189 190 static { 191 try { 192 Security.addProvider(new BouncyCastleProvider()); 193 } catch (Exception e) { 194 e.printStackTrace(); 195 } 196 } 197 198 /** 199 * 自定義註冊登記操做類 200 * 201 * @author yangyi47 202 * 203 */ 204 static final class StoreEnrollement implements Enrollment, Serializable { 205 206 private static final long serialVersionUID = 6965341351799577442L; 207 208 /** 私鑰 */ 209 private final PrivateKey privateKey; 210 /** 受權證書 */ 211 private final String certificate; 212 213 StoreEnrollement(PrivateKey privateKey, String certificate) { 214 this.certificate = certificate; 215 this.privateKey = privateKey; 216 } 217 218 @Override 219 public PrivateKey getKey() { 220 return privateKey; 221 } 222 223 @Override 224 public String getCert() { 225 return certificate; 226 } 227 } 228 229 }
1 package cn.aberic.fabric; 2 3 import java.io.File; 4 5 import org.apache.log4j.Logger; 6 7 import cn.aberic.fabric.bean.Chaincode; 8 import cn.aberic.fabric.bean.Orderers; 9 import cn.aberic.fabric.bean.Peers; 10 11 public class FabricConfig { 12 13 private static Logger log = Logger.getLogger(FabricConfig.class); 14 15 /** 節點服務器對象 */ 16 private Peers peers; 17 /** 排序服務器對象 */ 18 private Orderers orderers; 19 /** 智能合約對象 */ 20 private Chaincode chaincode; 21 /** channel-artifacts所在路徑:默認channel-artifacts所在路徑/xxx/WEB-INF/classes/fabric/channel-artifacts/ */ 22 private String channelArtifactsPath; 23 /** crypto-config所在路徑:默認crypto-config所在路徑/xxx/WEB-INF/classes/fabric/crypto-config/ */ 24 private String cryptoConfigPath; 25 private boolean registerEvent = false; 26 27 public FabricConfig() { 28 // 默認channel-artifacts所在路徑 /xxx/WEB-INF/classes/fabric/channel-artifacts/ 29 channelArtifactsPath = getChannlePath() + "/channel-artifacts/"; 30 // 默認crypto-config所在路徑 /xxx/WEB-INF/classes/fabric/crypto-config/ 31 cryptoConfigPath = getChannlePath() + "/crypto-config/"; 32 } 33 34 /** 35 * 默認fabric配置路徑 36 * 37 * @return D:/installSoft/apache-tomcat-9.0.0.M21-02/webapps/xxx/WEB-INF/classes/fabric/channel-artifacts/ 38 */ 39 private String getChannlePath() { 40 String directorys = ChaincodeManager.class.getClassLoader().getResource("fabric").getFile(); 41 log.debug("directorys = " + directorys); 42 File directory = new File(directorys); 43 log.debug("directory = " + directory.getPath()); 44 45 return directory.getPath(); 46 // return "src/main/resources/fabric/channel-artifacts/"; 47 } 48 49 public Peers getPeers() { 50 return peers; 51 } 52 53 public void setPeers(Peers peers) { 54 this.peers = peers; 55 } 56 57 public Orderers getOrderers() { 58 return orderers; 59 } 60 61 public void setOrderers(Orderers orderers) { 62 this.orderers = orderers; 63 } 64 65 public Chaincode getChaincode() { 66 return chaincode; 67 } 68 69 public void setChaincode(Chaincode chaincode) { 70 this.chaincode = chaincode; 71 } 72 73 public String getChannelArtifactsPath() { 74 return channelArtifactsPath; 75 } 76 77 public void setChannelArtifactsPath(String channelArtifactsPath) { 78 this.channelArtifactsPath = channelArtifactsPath; 79 } 80 81 public String getCryptoConfigPath() { 82 return cryptoConfigPath; 83 } 84 85 public void setCryptoConfigPath(String cryptoConfigPath) { 86 this.cryptoConfigPath = cryptoConfigPath; 87 } 88 89 public boolean isRegisterEvent() { 90 return registerEvent; 91 } 92 93 public void setRegisterEvent(boolean registerEvent) { 94 this.registerEvent = registerEvent; 95 } 96 97 }
1 package cn.aberic.fabric; 2 3 import static java.nio.charset.StandardCharsets.UTF_8; 4 5 import java.io.File; 6 import java.io.IOException; 7 import java.nio.file.Paths; 8 import java.security.NoSuchAlgorithmException; 9 import java.security.NoSuchProviderException; 10 import java.security.spec.InvalidKeySpecException; 11 import java.util.Collection; 12 import java.util.HashMap; 13 import java.util.LinkedList; 14 import java.util.Map; 15 import java.util.Properties; 16 import java.util.Set; 17 import java.util.concurrent.ExecutionException; 18 import java.util.concurrent.TimeoutException; 19 20 import org.apache.log4j.Logger; 21 import org.hyperledger.fabric.sdk.BlockEvent; 22 import org.hyperledger.fabric.sdk.BlockListener; 23 import org.hyperledger.fabric.sdk.ChaincodeID; 24 import org.hyperledger.fabric.sdk.Channel; 25 import org.hyperledger.fabric.sdk.HFClient; 26 import org.hyperledger.fabric.sdk.ProposalResponse; 27 import org.hyperledger.fabric.sdk.QueryByChaincodeRequest; 28 import org.hyperledger.fabric.sdk.SDKUtils; 29 import org.hyperledger.fabric.sdk.TransactionProposalRequest; 30 import org.hyperledger.fabric.sdk.exception.CryptoException; 31 import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; 32 import org.hyperledger.fabric.sdk.exception.ProposalException; 33 import org.hyperledger.fabric.sdk.exception.TransactionException; 34 import org.hyperledger.fabric.sdk.security.CryptoSuite; 35 36 import com.google.protobuf.ByteString; 37 import com.google.protobuf.InvalidProtocolBufferException; 38 39 import cn.aberic.fabric.bean.Chaincode; 40 import cn.aberic.fabric.bean.Orderers; 41 import cn.aberic.fabric.bean.Peers; 42 43 public class ChaincodeManager { 44 45 private static Logger log = Logger.getLogger(ChaincodeManager.class); 46 47 private FabricConfig config; 48 private Orderers orderers; 49 private Peers peers; 50 private Chaincode chaincode; 51 52 private HFClient client; 53 private FabricOrg fabricOrg; 54 private Channel channel; 55 private ChaincodeID chaincodeID; 56 57 public ChaincodeManager(FabricConfig fabricConfig) 58 throws CryptoException, InvalidArgumentException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException, TransactionException { 59 this.config = fabricConfig; 60 61 orderers = this.config.getOrderers(); 62 peers = this.config.getPeers(); 63 chaincode = this.config.getChaincode(); 64 65 client = HFClient.createNewInstance(); 66 log.debug("Create instance of HFClient"); 67 client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite()); 68 log.debug("Set Crypto Suite of HFClient"); 69 70 fabricOrg = getFabricOrg(); 71 channel = getChannel(); 72 chaincodeID = getChaincodeID(); 73 74 client.setUserContext(fabricOrg.getPeerAdmin()); // 也許是1.0.0測試版的bug,只有節點管理員能夠調用鏈碼 75 } 76 77 private FabricOrg getFabricOrg() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException { 78 79 // java.io.tmpdir : C:\Users\yangyi47\AppData\Local\Temp\ 80 File storeFile = new File(System.getProperty("java.io.tmpdir") + "/HFCSampletest.properties"); 81 FabricStore fabricStore = new FabricStore(storeFile); 82 83 // Get Org1 from configuration 84 FabricOrg fabricOrg = new FabricOrg(peers, orderers, fabricStore, config.getCryptoConfigPath()); 85 log.debug("Get FabricOrg"); 86 return fabricOrg; 87 } 88 89 private Channel getChannel() 90 throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException, CryptoException, InvalidArgumentException, TransactionException { 91 client.setUserContext(fabricOrg.getPeerAdmin()); 92 return getChannel(fabricOrg, client); 93 } 94 95 private Channel getChannel(FabricOrg fabricOrg, HFClient client) 96 throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException, CryptoException, InvalidArgumentException, TransactionException { 97 Channel channel = client.newChannel(chaincode.getChannelName()); 98 log.debug("Get Chain " + chaincode.getChannelName()); 99 100 // channel.setTransactionWaitTime(chaincode.getInvokeWatiTime()); 101 // channel.setDeployWaitTime(chaincode.getDeployWatiTime()); 102 103 for (int i = 0; i < peers.get().size(); i++) { 104 File peerCert = Paths.get(config.getCryptoConfigPath(), "/peerOrganizations", peers.getOrgDomainName(), "peers", peers.get().get(i).getPeerName(), "tls/server.crt") 105 .toFile(); 106 if (!peerCert.exists()) { 107 throw new RuntimeException( 108 String.format("Missing cert file for: %s. Could not find at location: %s", peers.get().get(i).getPeerName(), peerCert.getAbsolutePath())); 109 } 110 Properties peerProperties = new Properties(); 111 peerProperties.setProperty("pemFile", peerCert.getAbsolutePath()); 112 // ret.setProperty("trustServerCertificate", "true"); //testing 113 // environment only NOT FOR PRODUCTION! 114 peerProperties.setProperty("hostnameOverride", peers.getOrgDomainName()); 115 peerProperties.setProperty("sslProvider", "openSSL"); 116 peerProperties.setProperty("negotiationType", "TLS"); 117 // 在grpc的NettyChannelBuilder上設置特定選項 118 peerProperties.put("grpc.ManagedChannelBuilderOption.maxInboundMessageSize", 9000000); 119 channel.addPeer(client.newPeer(peers.get().get(i).getPeerName(), fabricOrg.getPeerLocation(peers.get().get(i).getPeerName()), peerProperties)); 120 if (peers.get().get(i).isAddEventHub()) { 121 channel.addEventHub( 122 client.newEventHub(peers.get().get(i).getPeerEventHubName(), fabricOrg.getEventHubLocation(peers.get().get(i).getPeerEventHubName()), peerProperties)); 123 } 124 } 125 126 for (int i = 0; i < orderers.get().size(); i++) { 127 File ordererCert = Paths.get(config.getCryptoConfigPath(), "/ordererOrganizations", orderers.getOrdererDomainName(), "orderers", orderers.get().get(i).getOrdererName(), 128 "tls/server.crt").toFile(); 129 if (!ordererCert.exists()) { 130 throw new RuntimeException( 131 String.format("Missing cert file for: %s. Could not find at location: %s", orderers.get().get(i).getOrdererName(), ordererCert.getAbsolutePath())); 132 } 133 Properties ordererProperties = new Properties(); 134 ordererProperties.setProperty("pemFile", ordererCert.getAbsolutePath()); 135 ordererProperties.setProperty("hostnameOverride", orderers.getOrdererDomainName()); 136 ordererProperties.setProperty("sslProvider", "openSSL"); 137 ordererProperties.setProperty("negotiationType", "TLS"); 138 ordererProperties.put("grpc.ManagedChannelBuilderOption.maxInboundMessageSize", 9000000); 139 ordererProperties.setProperty("ordererWaitTimeMilliSecs", "300000"); 140 channel.addOrderer( 141 client.newOrderer(orderers.get().get(i).getOrdererName(), fabricOrg.getOrdererLocation(orderers.get().get(i).getOrdererName()), ordererProperties)); 142 } 143 144 log.debug("channel.isInitialized() = " + channel.isInitialized()); 145 if (!channel.isInitialized()) { 146 channel.initialize(); 147 } 148 if (config.isRegisterEvent()) { 149 channel.registerBlockListener(new BlockListener() { 150 151 @Override 152 public void received(BlockEvent event) { 153 // TODO 154 log.debug("========================Event事件監聽開始========================"); 155 try { 156 log.debug("event.getChannelId() = " + event.getChannelId()); 157 log.debug("event.getEvent().getChaincodeEvent().getPayload().toStringUtf8() = " + event.getEvent().getChaincodeEvent().getPayload().toStringUtf8()); 158 log.debug("event.getBlock().getData().getDataList().size() = " + event.getBlock().getData().getDataList().size()); 159 ByteString byteString = event.getBlock().getData().getData(0); 160 String result = byteString.toStringUtf8(); 161 log.debug("byteString.toStringUtf8() = " + result); 162 163 String r1[] = result.split("END CERTIFICATE"); 164 String rr = r1[2]; 165 log.debug("rr = " + rr); 166 } catch (InvalidProtocolBufferException e) { 167 // TODO 168 e.printStackTrace(); 169 } 170 log.debug("========================Event事件監聽結束========================"); 171 } 172 }); 173 } 174 return channel; 175 } 176 177 private ChaincodeID getChaincodeID() { 178 return ChaincodeID.newBuilder().setName(chaincode.getChaincodeName()).setVersion(chaincode.getChaincodeVersion()).setPath(chaincode.getChaincodePath()).build(); 179 } 180 181 /** 182 * 執行智能合約 183 * 184 * @param fcn 185 * 方法名 186 * @param args 187 * 參數數組 188 * @return 189 * @throws InvalidArgumentException 190 * @throws ProposalException 191 * @throws InterruptedException 192 * @throws ExecutionException 193 * @throws TimeoutException 194 * @throws IOException 195 * @throws TransactionException 196 * @throws CryptoException 197 * @throws InvalidKeySpecException 198 * @throws NoSuchProviderException 199 * @throws NoSuchAlgorithmException 200 */ 201 public Map<String, String> invoke(String fcn, String[] args) 202 throws InvalidArgumentException, ProposalException, InterruptedException, ExecutionException, TimeoutException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CryptoException, TransactionException, IOException { 203 Map<String, String> resultMap = new HashMap<>(); 204 205 Collection<ProposalResponse> successful = new LinkedList<>(); 206 Collection<ProposalResponse> failed = new LinkedList<>(); 207 208 /// Send transaction proposal to all peers 209 TransactionProposalRequest transactionProposalRequest = client.newTransactionProposalRequest(); 210 transactionProposalRequest.setChaincodeID(chaincodeID); 211 transactionProposalRequest.setFcn(fcn); 212 transactionProposalRequest.setArgs(args); 213 214 Map<String, byte[]> tm2 = new HashMap<>(); 215 tm2.put("HyperLedgerFabric", "TransactionProposalRequest:JavaSDK".getBytes(UTF_8)); 216 tm2.put("method", "TransactionProposalRequest".getBytes(UTF_8)); 217 tm2.put("result", ":)".getBytes(UTF_8)); 218 transactionProposalRequest.setTransientMap(tm2); 219 220 Collection<ProposalResponse> transactionPropResp = channel.sendTransactionProposal(transactionProposalRequest, channel.getPeers()); 221 for (ProposalResponse response : transactionPropResp) { 222 if (response.getStatus() == ProposalResponse.Status.SUCCESS) { 223 successful.add(response); 224 } else { 225 failed.add(response); 226 } 227 } 228 229 Collection<Set<ProposalResponse>> proposalConsistencySets = SDKUtils.getProposalConsistencySets(transactionPropResp); 230 if (proposalConsistencySets.size() != 1) { 231 log.error("Expected only one set of consistent proposal responses but got " + proposalConsistencySets.size()); 232 } 233 234 if (failed.size() > 0) { 235 ProposalResponse firstTransactionProposalResponse = failed.iterator().next(); 236 log.error("Not enough endorsers for inspect:" + failed.size() + " endorser error: " + firstTransactionProposalResponse.getMessage() + ". Was verified: " 237 + firstTransactionProposalResponse.isVerified()); 238 resultMap.put("code", "error"); 239 resultMap.put("data", firstTransactionProposalResponse.getMessage()); 240 return resultMap; 241 } else { 242 log.info("Successfully received transaction proposal responses."); 243 ProposalResponse resp = transactionPropResp.iterator().next(); 244 byte[] x = resp.getChaincodeActionResponsePayload(); 245 String resultAsString = null; 246 if (x != null) { 247 resultAsString = new String(x, "UTF-8"); 248 } 249 log.info("resultAsString = " + resultAsString); 250 channel.sendTransaction(successful); 251 resultMap.put("code", "success"); 252 resultMap.put("data", resultAsString); 253 return resultMap; 254 } 255 256 // channel.sendTransaction(successful).thenApply(transactionEvent -> { 257 // if (transactionEvent.isValid()) { 258 // log.info("Successfully send transaction proposal to orderer. Transaction ID: " + transactionEvent.getTransactionID()); 259 // } else { 260 // log.info("Failed to send transaction proposal to orderer"); 261 // } 262 // // chain.shutdown(true); 263 // return transactionEvent.getTransactionID(); 264 // }).get(chaincode.getInvokeWatiTime(), TimeUnit.SECONDS); 265 } 266 267 /** 268 * 查詢智能合約 269 * 270 * @param fcn 271 * 方法名 272 * @param args 273 * 參數數組 274 * @return 275 * @throws InvalidArgumentException 276 * @throws ProposalException 277 * @throws IOException 278 * @throws TransactionException 279 * @throws CryptoException 280 * @throws InvalidKeySpecException 281 * @throws NoSuchProviderException 282 * @throws NoSuchAlgorithmException 283 */ 284 public Map<String, String> query(String fcn, String[] args) throws InvalidArgumentException, ProposalException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CryptoException, TransactionException, IOException { 285 Map<String, String> resultMap = new HashMap<>(); 286 String payload = ""; 287 QueryByChaincodeRequest queryByChaincodeRequest = client.newQueryProposalRequest(); 288 queryByChaincodeRequest.setArgs(args); 289 queryByChaincodeRequest.setFcn(fcn); 290 queryByChaincodeRequest.setChaincodeID(chaincodeID); 291 292 Map<String, byte[]> tm2 = new HashMap<>(); 293 tm2.put("HyperLedgerFabric", "QueryByChaincodeRequest:JavaSDK".getBytes(UTF_8)); 294 tm2.put("method", "QueryByChaincodeRequest".getBytes(UTF_8)); 295 queryByChaincodeRequest.setTransientMap(tm2); 296 297 Collection<ProposalResponse> queryProposals = channel.queryByChaincode(queryByChaincodeRequest, channel.getPeers()); 298 for (ProposalResponse proposalResponse : queryProposals) { 299 if (!proposalResponse.isVerified() || proposalResponse.getStatus() != ProposalResponse.Status.SUCCESS) { 300 log.debug("Failed query proposal from peer " + proposalResponse.getPeer().getName() + " status: " + proposalResponse.getStatus() + ". Messages: " 301 + proposalResponse.getMessage() + ". Was verified : " + proposalResponse.isVerified()); 302 resultMap.put("code", "error"); 303 resultMap.put("data", "Failed query proposal from peer " + proposalResponse.getPeer().getName() + " status: " + proposalResponse.getStatus() + ". Messages: " 304 + proposalResponse.getMessage() + ". Was verified : " + proposalResponse.isVerified()); 305 } else { 306 payload = proposalResponse.getProposalResponse().getResponse().getPayload().toStringUtf8(); 307 log.debug("Query payload from peer: " + proposalResponse.getPeer().getName()); 308 log.debug("" + payload); 309 resultMap.put("code", "success"); 310 resultMap.put("data", payload); 311 } 312 } 313 return resultMap; 314 } 315 316 }
請注意,用法主要都依賴於ChaincodeManager這個智能合約管理器,建議以單例的形式生成該對象。
插入數據調用 manager.invoke(fcn, arguments)
查詢數據調用 manager.query(fcn, arguments)
第一個參數是方法名,第二個參數是智能合約中的args字符串數組
切記不要用invoke來執行查詢操做,一來不必,二來該操做會生成數據集,且數據集也會發送給排序服務器,得不償失。