Hyperledger Fabric 1.0 从零开始(十)——智能合约(参阅:Hyperledger Fabric Chaincode for Operators——实操智能合约)
Hyperledger Fabric 1.0 从零开始(十一)——CouchDB(参阅:Hyperledger Fabric CouchDB as the State Database——使用CouchDB)
上述两章,最近网上各路大神文章云集,方案多多,因为最近工作太忙太忙,我暂时就先不赘述了,可以优先参考深蓝大大的文章HyperLedger Fabric ChainCode开发——shim.ChaincodeStubInterface用法。
这章先捡大家都比较在意的java sdk应用方案贴出来,很多朋友都找我要过,我主要是把注释都写进去了,用法简单了说了下,一般情况下会java开发的都能看懂。
年前实在太忙。
JAVA-SDK
9.1、基本介绍
官方在Fabric1.0之后就推荐使用SDK来实现交互的操作,原本在0.6上的restapi已经被废弃。JAVA-SDK可以参考github。官方给的SDK的DEMO很难入手,注释稀少内容还很杂,所幸感谢github上有位朋友(具体地址实在是找不到了,以后会补上)稍加整理了一下,直接重写了官方的DEMO,让像我这样的新人更容易入手。
本次在官方SDK和大神重新的DEMO的基础上做了一次整理,能够更加清晰简单的入门并使用JAVA-SDK来进行交互。
9.2、架构
相信看到这里的朋友应该都对Fabric已经有了足够的了解,至少是应用层上已经可以实现分布式账本的各项功能,sdk也是在这样的基础进行讲述。
首先看下针对JAVA-SDK所写的辅助工程目录
关于Fabric,我们知道一个channel中可以创建多个chaincode,而一个chaincode需要指定对应orderer和peer。
所以,在此建立了一个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 – 联盟存储配置对象
9.3、具体实现
直接通过代码来看实现
9.3.1、Chaincode代码
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 }
9.3.2、Orderers代码
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 }
9.3.3、Peers代码
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 }
9.3.4、FabricUser代码
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 }
9.3.5、FabricOrg代码
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 }
9.3.6、FabricStore代码
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 }
9.3.7、FabricConfig代码
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 }
9.3.8、ChaincodeManager代码
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来执行查询操作,一来没必要,二来该操作会生成数据集,且数据集也会发送给排序服务器,得不偿失。