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来执行查询操作,一来没必要,二来该操作会生成数据集,且数据集也会发送给排序服务器,得不偿失。
