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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fabric/block_decoder.rb +299 -0
  3. data/lib/fabric/chaincode_response.rb +47 -0
  4. data/lib/fabric/channel.rb +55 -34
  5. data/lib/fabric/client.rb +107 -25
  6. data/lib/fabric/configuration.rb +12 -4
  7. data/lib/fabric/constants.rb +1 -1
  8. data/lib/fabric/crypto_suite.rb +145 -0
  9. data/lib/fabric/enumerator_queue.rb +26 -0
  10. data/lib/fabric/error.rb +52 -0
  11. data/lib/fabric/event_hub.rb +81 -0
  12. data/lib/fabric/helper.rb +31 -0
  13. data/lib/fabric/identity.rb +25 -19
  14. data/lib/fabric/logger.rb +37 -0
  15. data/lib/fabric/orderer.rb +18 -2
  16. data/lib/fabric/peer.rb +15 -36
  17. data/lib/fabric/proposal.rb +100 -0
  18. data/lib/{protos → fabric/protos}/common/collection_pb.rb +14 -14
  19. data/lib/{protos → fabric/protos}/common/common_pb.rb +37 -36
  20. data/lib/fabric/protos/common/configtx_pb.rb +71 -0
  21. data/lib/{protos → fabric/protos}/common/configuration_pb.rb +13 -13
  22. data/lib/{protos → fabric/protos}/common/ledger_pb.rb +2 -2
  23. data/lib/{protos → fabric/protos}/common/policies_pb.rb +19 -19
  24. data/lib/fabric/protos/discovery/protocol_pb.rb +120 -0
  25. data/lib/{protos → fabric/protos}/discovery/protocol_services_pb.rb +0 -1
  26. data/lib/fabric/protos/gossip/message_pb.rb +233 -0
  27. data/lib/{protos → fabric/protos}/gossip/message_services_pb.rb +0 -1
  28. data/lib/{protos → fabric/protos}/idemix/idemix_pb.rb +37 -37
  29. data/lib/{protos → fabric/protos}/ledger/queryresult/kv_query_result_pb.rb +5 -5
  30. data/lib/fabric/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +85 -0
  31. data/lib/fabric/protos/ledger/rwset/rwset_pb.rb +46 -0
  32. data/lib/{protos → fabric/protos}/msp/identities_pb.rb +4 -4
  33. data/lib/{protos → fabric/protos}/msp/msp_config_pb.rb +27 -27
  34. data/lib/{protos → fabric/protos}/msp/msp_principal_pb.rb +20 -20
  35. data/lib/fabric/protos/orderer/ab_pb.rb +52 -0
  36. data/lib/{protos → fabric/protos}/orderer/ab_services_pb.rb +0 -1
  37. data/lib/fabric/protos/orderer/cluster_pb.rb +31 -0
  38. data/lib/fabric/protos/orderer/cluster_services_pb.rb +31 -0
  39. data/lib/{protos → fabric/protos}/orderer/configuration_pb.rb +11 -10
  40. data/lib/fabric/protos/orderer/etcdraft/configuration_pb.rb +21 -0
  41. data/lib/{protos → fabric/protos}/orderer/kafka_pb.rb +16 -16
  42. data/lib/{protos → fabric/protos}/peer/admin_pb.rb +12 -12
  43. data/lib/{protos → fabric/protos}/peer/admin_services_pb.rb +0 -1
  44. data/lib/{protos → fabric/protos}/peer/chaincode_event_pb.rb +2 -2
  45. data/lib/fabric/protos/peer/chaincode_pb.rb +60 -0
  46. data/lib/fabric/protos/peer/chaincode_shim_pb.rb +129 -0
  47. data/lib/{protos → fabric/protos}/peer/chaincode_shim_services_pb.rb +0 -1
  48. data/lib/{protos → fabric/protos}/peer/configuration_pb.rb +10 -10
  49. data/lib/fabric/protos/peer/events_pb.rb +45 -0
  50. data/lib/fabric/protos/peer/events_services_pb.rb +34 -0
  51. data/lib/{protos → fabric/protos}/peer/peer_pb.rb +5 -5
  52. data/lib/{protos → fabric/protos}/peer/peer_services_pb.rb +0 -1
  53. data/lib/{protos → fabric/protos}/peer/proposal_pb.rb +13 -13
  54. data/lib/{protos → fabric/protos}/peer/proposal_response_pb.rb +11 -11
  55. data/lib/{protos → fabric/protos}/peer/query_pb.rb +10 -10
  56. data/lib/{protos → fabric/protos}/peer/resources_pb.rb +12 -12
  57. data/lib/{protos → fabric/protos}/peer/signed_cc_dep_spec_pb.rb +3 -3
  58. data/lib/{protos → fabric/protos}/peer/transaction_pb.rb +22 -18
  59. data/lib/fabric/protos/token/prover_pb.rb +66 -0
  60. data/lib/fabric/protos/token/prover_services_pb.rb +33 -0
  61. data/lib/fabric/protos/token/transaction_pb.rb +41 -0
  62. data/lib/{protos → fabric/protos}/transientstore/transientstore_pb.rb +4 -4
  63. data/lib/fabric/queue.rb +26 -0
  64. data/lib/fabric/transaction.rb +51 -0
  65. data/lib/fabric/transaction_info.rb +20 -0
  66. data/lib/fabric/version.rb +1 -1
  67. data/lib/fabric.rb +74 -0
  68. data/lib/fabric_ca/attribute.rb +7 -0
  69. data/lib/fabric_ca/client.rb +11 -19
  70. data/lib/fabric_ca/configuration.rb +4 -2
  71. data/lib/fabric_ca/connection.rb +22 -20
  72. data/lib/fabric_ca/error.rb +3 -2
  73. data/lib/fabric_ca/faraday_middleware/basic_auth.rb +3 -3
  74. data/lib/fabric_ca/faraday_middleware/raise_http_exception.rb +13 -13
  75. data/lib/fabric_ca/faraday_middleware/token_auth.rb +10 -12
  76. data/lib/fabric_ca/request.rb +13 -24
  77. data/lib/fabric_ca/version.rb +1 -1
  78. data/lib/fabric_ca.rb +16 -0
  79. data/lib/hyperledger-fabric-sdk.rb +2 -47
  80. metadata +161 -61
  81. data/lib/crypto_suite/ecdsa_aes.rb +0 -86
  82. data/lib/fabric/peer_endorser.rb +0 -85
  83. data/lib/fabric/transaction_id.rb +0 -11
  84. data/lib/fabric/user.rb +0 -24
  85. data/lib/fabric_ca/tools.rb +0 -35
  86. data/lib/protos/common/configtx_pb.rb +0 -71
  87. data/lib/protos/discovery/protocol_pb.rb +0 -119
  88. data/lib/protos/gossip/message_pb.rb +0 -233
  89. data/lib/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +0 -85
  90. data/lib/protos/ledger/rwset/rwset_pb.rb +0 -46
  91. data/lib/protos/orderer/ab_pb.rb +0 -52
  92. data/lib/protos/peer/chaincode_pb.rb +0 -60
  93. data/lib/protos/peer/chaincode_shim_pb.rb +0 -94
  94. data/lib/protos/peer/events_pb.rb +0 -98
  95. 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: 8868d76ed70adc4cedf983ad30718b1964bdd4a4a06291bc336d7381bc152a74
4
- data.tar.gz: 97809db15dee6a3f8ac534a63eb3933895e8f0fa0ebd255b10569124e5ff06c4
3
+ metadata.gz: 526fd39f6b4ffb1466bd6cab26b3e36ff210c246d43cca39d22f403871ed8983
4
+ data.tar.gz: '068980d43804bb71cbcf30817bdaa39a711384dbd4b708a4e9fcd3dae027c17c'
5
5
  SHA512:
6
- metadata.gz: e4c1c49bdc093de69d552136954eacf30f0e92128222f5e878d760e71dd94ac08720ad832e8172014fb2363ce507963fe1099f1c7589878875c412704063de8f
7
- data.tar.gz: e91abaeeee3053694b18362ab2fff01132267782ae6fdc0e01ed8bcc04540ff565fa70ae6bd5e4931068664f8ae51230008792e3a9cf1592c23ba5284bead9e0
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
@@ -1,54 +1,75 @@
1
- require 'peer/transaction_pb'
2
-
3
1
  module Fabric
4
2
  class Channel
5
- attr_reader :identity_context, :name, :peers, :orderers
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
- def initialize(args)
8
- @identity_context = args[:identity_context]
9
- @name = args[:name]
10
- @peers = args[:peers] || []
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 query_by_chaincode(request)
15
- request[:targets] ||= peers
16
- request[:transaction] = TransactionID.new identity_context
15
+ def register_peer(url, opts = {})
16
+ @peers ||= []
17
17
 
18
- PeerEndorser.send_transaction_proposal request, name, identity_context
18
+ @peers << Peer.new(url: url, opts: opts, logger: logger)
19
19
  end
20
20
 
21
- def send_transaction(request, &block)
22
- header = Common::Header.decode request[:proposal].header
23
- chaincode_action_payload = build_chaincode_action request
21
+ def register_orderer(url, opts = {})
22
+ @orderers ||= []
24
23
 
25
- transaction_action = Protos::TransactionAction.new header: header.signature_header,
26
- payload: chaincode_action_payload.to_proto
27
- transaction = Protos::Transaction.new actions: [transaction_action]
24
+ @orderers << Orderer.new(url: url, opts: opts, logger: logger)
25
+ end
28
26
 
29
- payload = Common::Payload.new header: header,
30
- data: transaction.to_proto
27
+ def query(request = {})
28
+ request[:channel_id] = channel_id
31
29
 
32
- envelope = Common::Envelope.new signature: identity_context.identity.sign(payload.to_proto),
33
- payload: payload.to_proto
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
- orderers.first.send_broadcast envelope, &block
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
- def build_chaincode_action(request)
41
- responses = request[:responses].select { |response| response.response.status == 200 }
42
- endorsements = responses.map { |response| response.endorsement }
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
- payload = Protos::ChaincodeProposalPayload.decode request[:proposal].payload
48
- payload_no_trans = Protos::ChaincodeProposalPayload.new input: payload.input
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
- Protos::ChaincodeActionPayload.new action: chaincode_endorser_action,
51
- chaincode_proposal_payload: payload_no_trans.to_proto
52
- end
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 :identity_context, :orderers, :peers, :channels
3
+ attr_reader :identity, :crypto_suite,
4
+ :orderers, :peers, :logger
4
5
 
5
- def initialize(options = {})
6
- options = Fabric.options.merge(options)
6
+ MAX_ATTEMPTS_CHECK_TRANSACTION = 20
7
+ DELAY_PERIOD_CHECK_TRANSACTION = 2
7
8
 
8
- @identity_context = options[:identity_context]
9
- @orderers = {}
10
- @channels = {}
11
- @peers = {}
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
- def config
15
- conf = {}
16
- Configuration::VALID_OPTIONS_KEYS.each do |key|
17
- conf[key] = public_send key
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
- conf
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 new_channel(name)
24
- channels[name] ||= Channel.new name: name,
25
- orderers: orderers.values , peers: peers.values,
26
- identity_context: identity_context
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
- channels[name]
99
+ Protos::TxValidationCode.lookup processed_transaction.validationCode
29
100
  end
30
101
 
31
- def new_peer(url, opts = {})
32
- peers[url] ||= Peer.new url: url, opts: opts,
33
- identity_context: identity_context
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
- peers[url]
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 new_orderer(url, opts = {})
39
- orderers[url] ||= Orderer.new url: url, opts: opts,
40
- identity_context: identity_context
116
+ def parse_orderer_response(response)
117
+ raise OrdererError response.message unless response.status == :SUCCESS
118
+
119
+ response
120
+ end
41
121
 
42
- orderers[url]
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
@@ -1,14 +1,20 @@
1
1
  module Fabric
2
2
  module Configuration
3
- VALID_OPTIONS_KEYS = [:identity_context, :orderers, :peers]
3
+ DEFAULT_TIMEOUT = 30
4
4
 
5
- attr_accessor *VALID_OPTIONS_KEYS
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
@@ -13,6 +13,6 @@ module Fabric
13
13
  FUNC_GET_CONFIG_BLOCK = 'GetConfigBlock'.freeze
14
14
 
15
15
  ## Variables
16
- CHANNEL_HEADER_VERSION = 1.freeze
16
+ CHANNEL_HEADER_VERSION = 1
17
17
  end
18
18
  end