hyperledger-fabric-sdk 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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