hyperledger-fabric-sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fabric/block_decoder.rb +299 -0
- data/lib/fabric/chaincode_response.rb +47 -0
- data/lib/fabric/channel.rb +55 -34
- data/lib/fabric/client.rb +107 -25
- data/lib/fabric/configuration.rb +12 -4
- data/lib/fabric/constants.rb +1 -1
- data/lib/fabric/crypto_suite.rb +145 -0
- data/lib/fabric/enumerator_queue.rb +26 -0
- data/lib/fabric/error.rb +52 -0
- data/lib/fabric/event_hub.rb +81 -0
- data/lib/fabric/helper.rb +31 -0
- data/lib/fabric/identity.rb +25 -19
- data/lib/fabric/logger.rb +37 -0
- data/lib/fabric/orderer.rb +18 -2
- data/lib/fabric/peer.rb +15 -36
- data/lib/fabric/proposal.rb +100 -0
- data/lib/{protos → fabric/protos}/common/collection_pb.rb +14 -14
- data/lib/{protos → fabric/protos}/common/common_pb.rb +37 -36
- data/lib/fabric/protos/common/configtx_pb.rb +71 -0
- data/lib/{protos → fabric/protos}/common/configuration_pb.rb +13 -13
- data/lib/{protos → fabric/protos}/common/ledger_pb.rb +2 -2
- data/lib/{protos → fabric/protos}/common/policies_pb.rb +19 -19
- data/lib/fabric/protos/discovery/protocol_pb.rb +120 -0
- data/lib/{protos → fabric/protos}/discovery/protocol_services_pb.rb +0 -1
- data/lib/fabric/protos/gossip/message_pb.rb +233 -0
- data/lib/{protos → fabric/protos}/gossip/message_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/idemix/idemix_pb.rb +37 -37
- data/lib/{protos → fabric/protos}/ledger/queryresult/kv_query_result_pb.rb +5 -5
- data/lib/fabric/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +85 -0
- data/lib/fabric/protos/ledger/rwset/rwset_pb.rb +46 -0
- data/lib/{protos → fabric/protos}/msp/identities_pb.rb +4 -4
- data/lib/{protos → fabric/protos}/msp/msp_config_pb.rb +27 -27
- data/lib/{protos → fabric/protos}/msp/msp_principal_pb.rb +20 -20
- data/lib/fabric/protos/orderer/ab_pb.rb +52 -0
- data/lib/{protos → fabric/protos}/orderer/ab_services_pb.rb +0 -1
- data/lib/fabric/protos/orderer/cluster_pb.rb +31 -0
- data/lib/fabric/protos/orderer/cluster_services_pb.rb +31 -0
- data/lib/{protos → fabric/protos}/orderer/configuration_pb.rb +11 -10
- data/lib/fabric/protos/orderer/etcdraft/configuration_pb.rb +21 -0
- data/lib/{protos → fabric/protos}/orderer/kafka_pb.rb +16 -16
- data/lib/{protos → fabric/protos}/peer/admin_pb.rb +12 -12
- data/lib/{protos → fabric/protos}/peer/admin_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/peer/chaincode_event_pb.rb +2 -2
- data/lib/fabric/protos/peer/chaincode_pb.rb +60 -0
- data/lib/fabric/protos/peer/chaincode_shim_pb.rb +129 -0
- data/lib/{protos → fabric/protos}/peer/chaincode_shim_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/peer/configuration_pb.rb +10 -10
- data/lib/fabric/protos/peer/events_pb.rb +45 -0
- data/lib/fabric/protos/peer/events_services_pb.rb +34 -0
- data/lib/{protos → fabric/protos}/peer/peer_pb.rb +5 -5
- data/lib/{protos → fabric/protos}/peer/peer_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/peer/proposal_pb.rb +13 -13
- data/lib/{protos → fabric/protos}/peer/proposal_response_pb.rb +11 -11
- data/lib/{protos → fabric/protos}/peer/query_pb.rb +10 -10
- data/lib/{protos → fabric/protos}/peer/resources_pb.rb +12 -12
- data/lib/{protos → fabric/protos}/peer/signed_cc_dep_spec_pb.rb +3 -3
- data/lib/{protos → fabric/protos}/peer/transaction_pb.rb +22 -18
- data/lib/fabric/protos/token/prover_pb.rb +66 -0
- data/lib/fabric/protos/token/prover_services_pb.rb +33 -0
- data/lib/fabric/protos/token/transaction_pb.rb +41 -0
- data/lib/{protos → fabric/protos}/transientstore/transientstore_pb.rb +4 -4
- data/lib/fabric/queue.rb +26 -0
- data/lib/fabric/transaction.rb +51 -0
- data/lib/fabric/transaction_info.rb +20 -0
- data/lib/fabric/version.rb +1 -1
- data/lib/fabric.rb +74 -0
- data/lib/fabric_ca/attribute.rb +7 -0
- data/lib/fabric_ca/client.rb +11 -19
- data/lib/fabric_ca/configuration.rb +4 -2
- data/lib/fabric_ca/connection.rb +22 -20
- data/lib/fabric_ca/error.rb +3 -2
- data/lib/fabric_ca/faraday_middleware/basic_auth.rb +3 -3
- data/lib/fabric_ca/faraday_middleware/raise_http_exception.rb +13 -13
- data/lib/fabric_ca/faraday_middleware/token_auth.rb +10 -12
- data/lib/fabric_ca/request.rb +13 -24
- data/lib/fabric_ca/version.rb +1 -1
- data/lib/fabric_ca.rb +16 -0
- data/lib/hyperledger-fabric-sdk.rb +2 -47
- metadata +161 -61
- data/lib/crypto_suite/ecdsa_aes.rb +0 -86
- data/lib/fabric/peer_endorser.rb +0 -85
- data/lib/fabric/transaction_id.rb +0 -11
- data/lib/fabric/user.rb +0 -24
- data/lib/fabric_ca/tools.rb +0 -35
- data/lib/protos/common/configtx_pb.rb +0 -71
- data/lib/protos/discovery/protocol_pb.rb +0 -119
- data/lib/protos/gossip/message_pb.rb +0 -233
- data/lib/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +0 -85
- data/lib/protos/ledger/rwset/rwset_pb.rb +0 -46
- data/lib/protos/orderer/ab_pb.rb +0 -52
- data/lib/protos/peer/chaincode_pb.rb +0 -60
- data/lib/protos/peer/chaincode_shim_pb.rb +0 -94
- data/lib/protos/peer/events_pb.rb +0 -98
- data/lib/protos/peer/events_services_pb.rb +0 -59
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 526fd39f6b4ffb1466bd6cab26b3e36ff210c246d43cca39d22f403871ed8983
|
|
4
|
+
data.tar.gz: '068980d43804bb71cbcf30817bdaa39a711384dbd4b708a4e9fcd3dae027c17c'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a87997e6303f440171c13a291a23cc1c5bf4c67e56aad7f5665f8ca1c39f5178684510104de55b2d7c7e4a78f4eb271d95de3f128677af27ee86efe501f57a20
|
|
7
|
+
data.tar.gz: e31ddad32d3a636dd10d2b02e21dfb517f66f417ee12796d6ea4751fb6fc61d69ae23407cce3e65a3fe0934af8209ebd9c92498aa78ae0f61a188196aab68875
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
module Fabric
|
|
2
|
+
class BlockDecoder
|
|
3
|
+
def self.decode_block(proposal_block)
|
|
4
|
+
{
|
|
5
|
+
header: decode_block_header(proposal_block),
|
|
6
|
+
data: decode_block_data(proposal_block.data),
|
|
7
|
+
metadata: decode_block_metadata(proposal_block.metadata)
|
|
8
|
+
}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def self.decode_block_metadata(proto_block_metadata)
|
|
14
|
+
return {} unless proto_block_metadata.metadata
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
metadata: [
|
|
18
|
+
decode_metadata_signatures(proto_block_metadata.metadata[0]),
|
|
19
|
+
decode_last_config_sequence_number(proto_block_metadata.metadata[1]),
|
|
20
|
+
decode_transaction_filter(proto_block_metadata.metadata[2])
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.decode_transaction_filter(metadata_data)
|
|
26
|
+
return unless metadata_data
|
|
27
|
+
|
|
28
|
+
metadata_data.bytes
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.decode_last_config_sequence_number(metadata_data)
|
|
32
|
+
return { value: {} } unless metadata_data
|
|
33
|
+
|
|
34
|
+
proto_metadata = Common::Metadata.decode(metadata_data)
|
|
35
|
+
proto_last_config = Common::LastConfig.decode(proto_metadata.value)
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
value: {
|
|
39
|
+
index: proto_last_config.index
|
|
40
|
+
},
|
|
41
|
+
signatures: decode_metadata_value_signatures(proto_metadata.signatures)
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.decode_metadata_signatures(metadata_data)
|
|
46
|
+
proto_metadata = Common::Metadata.decode(metadata_data)
|
|
47
|
+
|
|
48
|
+
{
|
|
49
|
+
value: proto_metadata.value,
|
|
50
|
+
signatures: decode_metadata_value_signatures(proto_metadata.signatures)
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def decode_metadata_value_signatures(proto_meta_signatures)
|
|
55
|
+
Array.wrap(proto_meta_signatures).map do |meta_signature_data|
|
|
56
|
+
proto_metadata_signature = Common::MetadataSignature.decode(meta_signature_data)
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
signature_header: decode_signature_header(proto_metadata_signature.signature_header),
|
|
60
|
+
signature: Fabric.crypto_suite.encode_hex(proto_metadata_signature.signature)
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.decode_metadata_value_signatures(proto_meta_signatures); end
|
|
66
|
+
|
|
67
|
+
def self.decode_block_header(block_data)
|
|
68
|
+
{
|
|
69
|
+
number: block_data.header.number,
|
|
70
|
+
previous_hash: Fabric.crypto_suite.encode_hex(block_data.header.previous_hash),
|
|
71
|
+
data_hash: Fabric.crypto_suite.encode_hex(block_data.header.data_hash)
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.decode_block_data(proto_block_data)
|
|
76
|
+
data = { data: [] }
|
|
77
|
+
|
|
78
|
+
proto_block_data.data.each do |envelope_data|
|
|
79
|
+
proto_envelope = Common::Envelope.decode envelope_data
|
|
80
|
+
|
|
81
|
+
data[:data].push decode_block_data_envelope(proto_envelope)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
data
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.decode_block_data_envelope(proto_envelope)
|
|
88
|
+
envelope = { payload: {} }
|
|
89
|
+
envelope[:signature] = Fabric.crypto_suite.encode_hex proto_envelope.signature
|
|
90
|
+
proto_payload = Common::Payload.decode(proto_envelope.payload)
|
|
91
|
+
envelope[:payload][:header] = decode_payload_header proto_payload.header
|
|
92
|
+
envelope[:payload][:data] =
|
|
93
|
+
decode_payload_based_on_type proto_payload.data,
|
|
94
|
+
envelope[:payload][:header][:channel_header][:type]
|
|
95
|
+
|
|
96
|
+
envelope
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.decode_payload_header(proto_header)
|
|
100
|
+
header = {}
|
|
101
|
+
header[:channel_header] = decode_channel_header proto_header.channel_header
|
|
102
|
+
header[:signature_header] = decode_signature_header proto_header.signature_header
|
|
103
|
+
|
|
104
|
+
header
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.decode_channel_header(channel_header_data)
|
|
108
|
+
channel_header = {}
|
|
109
|
+
|
|
110
|
+
proto_channel_header = Common::ChannelHeader.decode channel_header_data
|
|
111
|
+
channel_header[:type] = proto_channel_header.type
|
|
112
|
+
channel_header[:version] = proto_channel_header.version
|
|
113
|
+
channel_header[:timestamp] = Helper.timestamp_to_time proto_channel_header.timestamp
|
|
114
|
+
channel_header[:channel_id] = proto_channel_header.channel_id
|
|
115
|
+
channel_header[:tx_id] = proto_channel_header.tx_id
|
|
116
|
+
channel_header[:epoch] = proto_channel_header.epoch
|
|
117
|
+
channel_header[:extension] = decode_payload_header_extension proto_channel_header.extension
|
|
118
|
+
|
|
119
|
+
channel_header
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def self.decode_payload_header_extension(extension_data)
|
|
123
|
+
return unless extension_data
|
|
124
|
+
|
|
125
|
+
Protos::ChaincodeHeaderExtension.decode(extension_data).to_hash
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.decode_signature_header(signature_header_data)
|
|
129
|
+
signature_header = {}
|
|
130
|
+
proto_signature_header = Common::SignatureHeader.decode signature_header_data
|
|
131
|
+
signature_header[:creator] = decode_identity proto_signature_header.creator
|
|
132
|
+
signature_header[:nonce] = Fabric.crypto_suite.encode_hex proto_signature_header.nonce
|
|
133
|
+
|
|
134
|
+
signature_header
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.decode_identity(creator_data)
|
|
138
|
+
identity = {}
|
|
139
|
+
|
|
140
|
+
proto_identity = Msp::SerializedIdentity.decode creator_data
|
|
141
|
+
identity[:mspid] = proto_identity.mspid
|
|
142
|
+
identity[:id_bytes] = proto_identity.id_bytes
|
|
143
|
+
|
|
144
|
+
identity
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.decode_payload_based_on_type(proto_data, type)
|
|
148
|
+
case type
|
|
149
|
+
when Common::HeaderType::CONFIG then {}
|
|
150
|
+
when Common::HeaderType::CONFIG_UPDATE then {}
|
|
151
|
+
when Common::HeaderType::ENDORSER_TRANSACTION then decode_endorser_transaction proto_data
|
|
152
|
+
else {}
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.decode_endorser_transaction(transaction_data)
|
|
157
|
+
proto_transaction = Protos::Transaction.decode transaction_data
|
|
158
|
+
|
|
159
|
+
{
|
|
160
|
+
actions: proto_transaction.actions.map do |proto_action|
|
|
161
|
+
{
|
|
162
|
+
header: decode_signature_header(proto_action.header),
|
|
163
|
+
payload: decode_chaincode_action_payload(proto_action.payload)
|
|
164
|
+
}
|
|
165
|
+
end
|
|
166
|
+
}
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def self.decode_chaincode_action_payload(payload_data)
|
|
170
|
+
proto_payload = Protos::ChaincodeActionPayload.decode payload_data
|
|
171
|
+
|
|
172
|
+
{
|
|
173
|
+
chaincode_proposal_payload:
|
|
174
|
+
decode_chaincode_proposal_payload(proto_payload.chaincode_proposal_payload),
|
|
175
|
+
action:
|
|
176
|
+
decode_chaincode_endorsed_action(proto_payload.action)
|
|
177
|
+
}
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def self.decode_chaincode_proposal_payload(payload_data)
|
|
181
|
+
proto_chaincode_proposal_payload = Protos::ChaincodeProposalPayload.decode payload_data
|
|
182
|
+
|
|
183
|
+
{
|
|
184
|
+
input: decode_chaincode_proposal_payload_input(proto_chaincode_proposal_payload.input)
|
|
185
|
+
}
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def self.decode_chaincode_proposal_payload_input(input_data)
|
|
189
|
+
Protos::ChaincodeInvocationSpec.decode(input_data).to_hash
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def self.decode_chaincode_input(input_data)
|
|
193
|
+
proto_chaincode_input = Protos::ChaincodeInput.decode input_data
|
|
194
|
+
|
|
195
|
+
proto_chaincode_input.to_hash
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def self.decode_chaincode_endorsed_action(proto_action)
|
|
199
|
+
{
|
|
200
|
+
proposal_response_payload:
|
|
201
|
+
decode_proposal_response_payload(proto_action.proposal_response_payload),
|
|
202
|
+
endorsements:
|
|
203
|
+
proto_action.endorsements.map do |proto_endorsement|
|
|
204
|
+
decode_endorsement proto_endorsement
|
|
205
|
+
end
|
|
206
|
+
}
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def self.decode_endorsement(proto_endorsement)
|
|
210
|
+
{
|
|
211
|
+
endorser: decode_identity(proto_endorsement.endorser),
|
|
212
|
+
signature: Fabric.crypto_suite.encode_hex(proto_endorsement.signature)
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def self.decode_proposal_response_payload(proposal_response_payload_bytes)
|
|
217
|
+
proposal_response_payload = {}
|
|
218
|
+
proto_proposal_response_payload =
|
|
219
|
+
Protos::ProposalResponsePayload.decode proposal_response_payload_bytes
|
|
220
|
+
proposal_response_payload[:proposal_hash] =
|
|
221
|
+
Fabric.crypto_suite.encode_hex proto_proposal_response_payload.proposal_hash
|
|
222
|
+
proposal_response_payload[:extension] =
|
|
223
|
+
decode_chaincode_action proto_proposal_response_payload.extension
|
|
224
|
+
|
|
225
|
+
proposal_response_payload
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def self.decode_chaincode_action(action_data)
|
|
229
|
+
proto_chaincode_action = Protos::ChaincodeAction.decode action_data
|
|
230
|
+
|
|
231
|
+
{
|
|
232
|
+
results: decode_read_write_sets(proto_chaincode_action.results),
|
|
233
|
+
events: decode_chaincode_events(proto_chaincode_action.events),
|
|
234
|
+
response: decode_response(proto_chaincode_action.response),
|
|
235
|
+
chaincode_id: decode_chaincode_id(proto_chaincode_action.chaincode_id)
|
|
236
|
+
}
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def self.decode_read_write_sets(rw_sets_data)
|
|
240
|
+
proto_tx_read_write_set = Rwset::TxReadWriteSet.decode rw_sets_data
|
|
241
|
+
tx_read_write_set = { data_model: proto_tx_read_write_set.data_model }
|
|
242
|
+
ns_rwset = proto_tx_read_write_set.ns_rwset
|
|
243
|
+
|
|
244
|
+
tx_read_write_set[:ns_rwset] =
|
|
245
|
+
if proto_tx_read_write_set.data_model == :KV
|
|
246
|
+
decode_ns_rwset ns_rwset
|
|
247
|
+
else
|
|
248
|
+
ns_rwset
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
tx_read_write_set
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def self.decode_ns_rwset(ns_rwset)
|
|
255
|
+
ns_rwset.map do |proto_ns_rwset|
|
|
256
|
+
{
|
|
257
|
+
namespace: proto_ns_rwset.namespace,
|
|
258
|
+
rwset: decode_kv_rw_set(proto_ns_rwset.rwset),
|
|
259
|
+
collection_hashed_rwset:
|
|
260
|
+
decode_collection_hashed_rw_set(proto_ns_rwset.collection_hashed_rwset)
|
|
261
|
+
}
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def self.decode_kv_rw_set(rwset_data)
|
|
266
|
+
Kvrwset::KVRWSet.decode(rwset_data).to_hash
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def self.decode_collection_hashed_rw_set(proto_collection_hashed_rwset)
|
|
270
|
+
proto_collection_hashed_rwset.map do |proto_hashed_rwset|
|
|
271
|
+
{
|
|
272
|
+
collection_name: proto_hashed_rwset.collection_name,
|
|
273
|
+
decode_hashed_rwset: decode_hashed_rwset(proto_hashed_rwset.hashed_rwset_data),
|
|
274
|
+
pvt_rwset_hash: proto_hashed_rwset.pvt_rwset_hash
|
|
275
|
+
}
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def self.decode_hashed_rwset(hashed_rwset_data)
|
|
280
|
+
Rwset::HashedRWSet.decode(hashed_rwset_data).to_hash
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def self.decode_chaincode_events(event_data)
|
|
284
|
+
Protos::ChaincodeEvent.decode(event_data).to_hash
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def self.decode_response(proposal_response)
|
|
288
|
+
return unless proposal_response
|
|
289
|
+
|
|
290
|
+
proposal_response.to_hash
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def self.decode_chaincode_id(chaincode_id)
|
|
294
|
+
return unless chaincode_id
|
|
295
|
+
|
|
296
|
+
chaincode_id.to_hash
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Fabric
|
|
2
|
+
class ChaincodeResponse
|
|
3
|
+
attr_reader :proposal, :proposal_responses, :responses
|
|
4
|
+
|
|
5
|
+
def initialize(attrs)
|
|
6
|
+
@proposal = attrs[:proposal]
|
|
7
|
+
@proposal_responses = attrs[:proposal_responses].compact
|
|
8
|
+
@responses = proposal_responses.map(&:response)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def success?
|
|
12
|
+
success_responses.any?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def success_responses
|
|
16
|
+
@success_responses ||= responses.select { |response| response.status == 200 }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def failure_response
|
|
20
|
+
@failure_response ||= responses.find { |response| response.status == 500 }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def tx_id
|
|
24
|
+
proposal.tx_id
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def tx_timestamp
|
|
28
|
+
proposal.tx_timestamp
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def tx_unix_timestamp
|
|
32
|
+
(tx_timestamp.seconds * 1000 + tx_timestamp.nanos / 10**6).to_i
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def payload
|
|
36
|
+
success_responses.first&.payload
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def validate!
|
|
40
|
+
return if success?
|
|
41
|
+
|
|
42
|
+
raise NetworkOfflineError if proposal_responses.empty?
|
|
43
|
+
|
|
44
|
+
raise ErrorFactory.create failure_response.message
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/fabric/channel.rb
CHANGED
|
@@ -1,54 +1,75 @@
|
|
|
1
|
-
require 'peer/transaction_pb'
|
|
2
|
-
|
|
3
1
|
module Fabric
|
|
4
2
|
class Channel
|
|
5
|
-
attr_reader :
|
|
3
|
+
attr_reader :identity, :crypto_suite, :channel_id,
|
|
4
|
+
:orderers, :peers, :logger
|
|
5
|
+
|
|
6
|
+
def initialize(opts = {})
|
|
7
|
+
options = Fabric.options.merge opts
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
@
|
|
9
|
-
@
|
|
10
|
-
@
|
|
11
|
-
@orderers = args[:orderers] || []
|
|
9
|
+
@channel_id = options[:channel_id]
|
|
10
|
+
@logger = Logger.new options[:logger], options[:logger_filters]
|
|
11
|
+
@identity = options[:identity]
|
|
12
|
+
@crypto_suite = options[:crypto_suite]
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
request[:transaction] = TransactionID.new identity_context
|
|
15
|
+
def register_peer(url, opts = {})
|
|
16
|
+
@peers ||= []
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
@peers << Peer.new(url: url, opts: opts, logger: logger)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
chaincode_action_payload = build_chaincode_action request
|
|
21
|
+
def register_orderer(url, opts = {})
|
|
22
|
+
@orderers ||= []
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
transaction = Protos::Transaction.new actions: [transaction_action]
|
|
24
|
+
@orderers << Orderer.new(url: url, opts: opts, logger: logger)
|
|
25
|
+
end
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
def query(request = {})
|
|
28
|
+
request[:channel_id] = channel_id
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
logging __method__, request
|
|
31
|
+
|
|
32
|
+
proposal = Proposal.new crypto_suite, identity, request
|
|
33
|
+
proposal_responses = peers.map { |peer| peer.send_process_proposal(proposal.signed_proposal) }
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
chaincode_response = ChaincodeResponse.new proposal: proposal,
|
|
36
|
+
proposal_responses: proposal_responses
|
|
37
|
+
|
|
38
|
+
chaincode_response.validate!
|
|
39
|
+
|
|
40
|
+
chaincode_response
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def invoke(chaincode_response)
|
|
44
|
+
transaction = Transaction.new crypto_suite,
|
|
45
|
+
identity,
|
|
46
|
+
proposal: chaincode_response.proposal,
|
|
47
|
+
responses: chaincode_response.proposal_responses
|
|
48
|
+
|
|
49
|
+
send_transaction transaction
|
|
50
|
+
|
|
51
|
+
chaincode_response
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def create_transaction_info
|
|
55
|
+
TransactionInfo.new crypto_suite, identity
|
|
36
56
|
end
|
|
37
57
|
|
|
38
58
|
private
|
|
39
59
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
chaincode_endorser_action =
|
|
44
|
-
Protos::ChaincodeEndorsedAction.new proposal_response_payload: responses.first.payload,
|
|
45
|
-
endorsements: endorsements
|
|
60
|
+
def send_transaction(transaction)
|
|
61
|
+
payload = Common::Payload.new header: transaction.header,
|
|
62
|
+
data: transaction.transaction.to_proto
|
|
46
63
|
|
|
47
|
-
|
|
48
|
-
|
|
64
|
+
envelope = Common::Envelope.new signature: identity.sign(payload.to_proto),
|
|
65
|
+
payload: payload.to_proto
|
|
66
|
+
|
|
67
|
+
orderers.each { |orderer| orderer.send_broadcast envelope }
|
|
68
|
+
end
|
|
49
69
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
70
|
+
def logging(section, message = {})
|
|
71
|
+
logger.info section.to_s.upcase.colorize(:yellow),
|
|
72
|
+
message.to_s.colorize(:blue)
|
|
73
|
+
end
|
|
53
74
|
end
|
|
54
75
|
end
|
data/lib/fabric/client.rb
CHANGED
|
@@ -1,45 +1,127 @@
|
|
|
1
1
|
module Fabric
|
|
2
2
|
class Client
|
|
3
|
-
attr_reader :
|
|
3
|
+
attr_reader :identity, :crypto_suite,
|
|
4
|
+
:orderers, :peers, :logger
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
MAX_ATTEMPTS_CHECK_TRANSACTION = 20
|
|
7
|
+
DELAY_PERIOD_CHECK_TRANSACTION = 2
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@
|
|
9
|
+
def initialize(opts = {})
|
|
10
|
+
options = Fabric.options.merge opts
|
|
11
|
+
|
|
12
|
+
@logger = Logger.new options[:logger], options[:logger_filters]
|
|
13
|
+
@identity = options[:identity]
|
|
14
|
+
@crypto_suite = options[:crypto_suite]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def register_peer(url, opts = {})
|
|
18
|
+
@peers ||= []
|
|
19
|
+
|
|
20
|
+
@peers << Peer.new(url: url, opts: opts, logger: logger)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def register_orderer(url, opts = {})
|
|
24
|
+
@orderers ||= []
|
|
25
|
+
|
|
26
|
+
@orderers << Orderer.new(url: url, opts: opts, logger: logger)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def query(request = {})
|
|
30
|
+
logging __method__, request
|
|
31
|
+
|
|
32
|
+
proposal = Proposal.new crypto_suite, identity, request
|
|
33
|
+
|
|
34
|
+
send_query(proposal) { |response| parse_chaincode_response response.response }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def invoke(request = {})
|
|
38
|
+
logging __method__, request
|
|
39
|
+
|
|
40
|
+
proposal = Proposal.new crypto_suite, identity, request
|
|
41
|
+
|
|
42
|
+
responses = send_query(proposal) { |response| parse_peer_response response }
|
|
43
|
+
|
|
44
|
+
transaction = Transaction.new crypto_suite, identity, proposal: proposal,
|
|
45
|
+
responses: responses
|
|
46
|
+
|
|
47
|
+
send_transaction(transaction) { |response| parse_orderer_response response }
|
|
48
|
+
|
|
49
|
+
responses.map { |response| parse_chaincode_response response.response }
|
|
12
50
|
end
|
|
13
51
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def send_query(proposal, &block)
|
|
55
|
+
peers.map do |peer|
|
|
56
|
+
peer_response = peer.send_process_proposal(proposal.signed_proposal)
|
|
57
|
+
|
|
58
|
+
block ? yield(peer_response) : peer_response
|
|
18
59
|
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def send_transaction(transaction, &block)
|
|
63
|
+
payload = Common::Payload.new header: transaction.header,
|
|
64
|
+
data: transaction.transaction.to_proto
|
|
65
|
+
|
|
66
|
+
envelope = Common::Envelope.new signature: identity.sign(payload.to_proto),
|
|
67
|
+
payload: payload.to_proto
|
|
68
|
+
|
|
69
|
+
orderers.each { |orderer| orderer.send_broadcast envelope, &block }
|
|
70
|
+
|
|
71
|
+
check_transaction transaction
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def check_transaction(transaction)
|
|
75
|
+
MAX_ATTEMPTS_CHECK_TRANSACTION.times do
|
|
76
|
+
begin
|
|
77
|
+
validation_code = get_transaction_validation_code transaction
|
|
19
78
|
|
|
20
|
-
|
|
79
|
+
logging __method__, tx_id: transaction.tx_id, status: validation_code
|
|
80
|
+
|
|
81
|
+
return validation_code if validation_code == :VALID
|
|
82
|
+
|
|
83
|
+
raise Fabric::TransactionError, validation_code
|
|
84
|
+
rescue UnknownError => ex
|
|
85
|
+
sleep DELAY_PERIOD_CHECK_TRANSACTION
|
|
86
|
+
|
|
87
|
+
logger.debug ex.message
|
|
88
|
+
end
|
|
89
|
+
end
|
|
21
90
|
end
|
|
22
91
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
92
|
+
def get_transaction_validation_code(transaction)
|
|
93
|
+
channel_id = transaction.proposal.channel_id
|
|
94
|
+
responses = query channel_id: channel_id,
|
|
95
|
+
chaincode_id: 'qscc',
|
|
96
|
+
args: ['GetTransactionByID', channel_id, transaction.tx_id]
|
|
97
|
+
processed_transaction = Protos::ProcessedTransaction.decode responses.first
|
|
27
98
|
|
|
28
|
-
|
|
99
|
+
Protos::TxValidationCode.lookup processed_transaction.validationCode
|
|
29
100
|
end
|
|
30
101
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
102
|
+
def parse_chaincode_response(response)
|
|
103
|
+
case response.status
|
|
104
|
+
when 200 then response.payload
|
|
105
|
+
when 500 then raise ErrorFactory.create(response.message)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
34
108
|
|
|
35
|
-
|
|
109
|
+
def parse_peer_response(response)
|
|
110
|
+
case response.response.status
|
|
111
|
+
when 200 then response
|
|
112
|
+
when 500 then raise ErrorFactory.create(response.response.message)
|
|
113
|
+
end
|
|
36
114
|
end
|
|
37
115
|
|
|
38
|
-
def
|
|
39
|
-
|
|
40
|
-
|
|
116
|
+
def parse_orderer_response(response)
|
|
117
|
+
raise OrdererError response.message unless response.status == :SUCCESS
|
|
118
|
+
|
|
119
|
+
response
|
|
120
|
+
end
|
|
41
121
|
|
|
42
|
-
|
|
122
|
+
def logging(section, message = {})
|
|
123
|
+
logger.info section.to_s.upcase.colorize(:yellow),
|
|
124
|
+
message.to_s.colorize(:blue)
|
|
43
125
|
end
|
|
44
126
|
end
|
|
45
127
|
end
|
data/lib/fabric/configuration.rb
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
module Fabric
|
|
2
2
|
module Configuration
|
|
3
|
-
|
|
3
|
+
DEFAULT_TIMEOUT = 30
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
VALID_OPTIONS_KEYS = %i[
|
|
6
|
+
crypto_suite identity orderers
|
|
7
|
+
channel_id peers timeout logger
|
|
8
|
+
logger_filters event_hub_url
|
|
9
|
+
].freeze
|
|
10
|
+
|
|
11
|
+
VALID_OPTIONS_KEYS.each { |attr| attr_accessor attr }
|
|
6
12
|
|
|
7
13
|
def self.extended(base)
|
|
8
14
|
base.reset
|
|
9
15
|
end
|
|
10
16
|
|
|
11
|
-
def configure
|
|
17
|
+
def self.configure
|
|
12
18
|
yield self
|
|
13
19
|
end
|
|
14
20
|
|
|
@@ -19,7 +25,9 @@ module Fabric
|
|
|
19
25
|
end
|
|
20
26
|
|
|
21
27
|
def reset
|
|
22
|
-
VALID_OPTIONS_KEYS.each {|key| send("#{key}=", nil)}
|
|
28
|
+
VALID_OPTIONS_KEYS.each { |key| send("#{key}=", nil) }
|
|
29
|
+
|
|
30
|
+
self.timeout = DEFAULT_TIMEOUT
|
|
23
31
|
end
|
|
24
32
|
end
|
|
25
33
|
end
|