fabric-gateway 0.0.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +3 -0
  3. data/.github/workflows/codeql-analysis.yml +71 -0
  4. data/.github/workflows/rspec.yml +37 -0
  5. data/.github/workflows/rubocop.yml +28 -0
  6. data/.github/workflows/todo.yml +10 -0
  7. data/.github/workflows/yardoc.yml +28 -0
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +23 -0
  10. data/.ruby-version +1 -0
  11. data/.vscode/settings.json +7 -0
  12. data/.yardopts +8 -0
  13. data/CODE_OF_CONDUCT.md +105 -46
  14. data/Gemfile +5 -3
  15. data/LICENSE.txt +1 -1
  16. data/README.md +123 -12
  17. data/Rakefile +6 -3
  18. data/bin/console +4 -3
  19. data/bin/regenerate +1 -0
  20. data/bin/release +5 -0
  21. data/fabric-gateway.gemspec +31 -17
  22. data/lib/fabric/accessors/contract.rb +51 -0
  23. data/lib/fabric/accessors/gateway.rb +33 -0
  24. data/lib/fabric/accessors/network.rb +40 -0
  25. data/lib/fabric/client.rb +199 -0
  26. data/lib/fabric/constants.rb +8 -0
  27. data/lib/fabric/contract.rb +178 -0
  28. data/lib/fabric/ec_crypto_suite.rb +199 -0
  29. data/lib/fabric/entities/chaincode_events_requests.rb +166 -0
  30. data/lib/fabric/entities/envelope.rb +158 -0
  31. data/lib/fabric/entities/identity.rb +87 -0
  32. data/lib/fabric/entities/proposal.rb +189 -0
  33. data/lib/fabric/entities/proposed_transaction.rb +163 -0
  34. data/lib/fabric/entities/status.rb +32 -0
  35. data/lib/fabric/entities/transaction.rb +247 -0
  36. data/lib/fabric/gateway.rb +31 -6
  37. data/lib/fabric/network.rb +70 -0
  38. data/lib/fabric/version.rb +5 -0
  39. data/lib/fabric.rb +59 -0
  40. data/lib/msp/identities_pb.rb +25 -0
  41. metadata +162 -13
  42. data/Gemfile.lock +0 -42
  43. data/lib/fabric/gateway/version.rb +0 -5
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fabric
4
+ #
5
+ # Proposal represents a transaction proposal that can be sent to peers for endorsement or evaluated as a query.
6
+ #
7
+ # Combined ProposalBuilder with Proposal. Utilizing instance variables and functions in proposal seem adaquate enough
8
+ # to fully create the proposal. ProposalBuilder did not seem like a native ruby design pattern.
9
+ class Proposal
10
+ attr_reader :proposed_transaction
11
+
12
+ #
13
+ # Instantiates a new Proposal
14
+ #
15
+ # @param [Fabric::ProposedTransaction] proposed_transaction ProposedTransaction container class
16
+ #
17
+ def initialize(proposed_transaction)
18
+ @proposed_transaction = proposed_transaction
19
+ end
20
+
21
+ def contract
22
+ @proposed_transaction.contract
23
+ end
24
+
25
+ include Fabric::Accessors::Contract
26
+
27
+ def transaction_id
28
+ proposed_transaction.transaction_id
29
+ end
30
+
31
+ #
32
+ # Returns the proposal message as a protobuf Message object.
33
+ #
34
+ # @return [Protos::Proposal|nil] Proposal message
35
+ #
36
+ def proposal
37
+ proposed_transaction.proposal
38
+ end
39
+
40
+ #
41
+ # Returns the signed proposal
42
+ #
43
+ # <rant>
44
+ # Fabric message naming scheme is a mess:
45
+ # ProposedTransaction has a Proposal which is a SignedProposal
46
+ # which has a Proposal which is a Proposal
47
+ # so.... which proposal do you want to access? Adding this function for clarity
48
+ # </rant>
49
+ #
50
+ # @return [Protos::SignedProposal|nil] SignedProposal message
51
+ #
52
+ def signed_proposal
53
+ proposed_transaction.proposed_transaction.proposal
54
+ end
55
+
56
+ #
57
+ # Serialized bytes of the proposal message in proto3 format.
58
+ #
59
+ # @return [String] Binary representation of the proposal message.
60
+ #
61
+ def to_proto
62
+ proposed_transaction.to_proto
63
+ end
64
+
65
+ #
66
+ # Proposal digest which can be utilized for offline signing.
67
+ # If signing offline, call signature= to set signature once
68
+ # computed.
69
+ #
70
+ # @return [String] raw binary digest of the proposal message.
71
+ #
72
+ def digest
73
+ Fabric.crypto_suite.digest(proposal.to_proto)
74
+ end
75
+
76
+ #
77
+ # Sets the signature of the signed proposal in the proposed transaction
78
+ #
79
+ # @param [String] signature raw byte string signature of the proposal message
80
+ # (should be the signature of the proposed message digest)
81
+ #
82
+ def signature=(signature)
83
+ proposed_transaction.signed_proposal.signature = signature
84
+ end
85
+
86
+ #
87
+ # Returns the signed proposal signature
88
+ #
89
+ # @return [String] Raw byte string signature
90
+ #
91
+ def signature
92
+ proposed_transaction.signed_proposal.signature
93
+ end
94
+
95
+ #
96
+ # Returns true if the signed proposal has a signature
97
+ #
98
+ # @return [Boolean] true|false
99
+ #
100
+ def signed?
101
+ # signature cannot be nil because google protobuf won't let it
102
+ !proposed_transaction.signed_proposal.signature.empty?
103
+ end
104
+
105
+ #
106
+ # Utilizes the signer to sign the proposal message if it has not been signed yet.
107
+ #
108
+ def sign
109
+ return if signed?
110
+
111
+ self.signature = signer.sign proposal.to_proto
112
+ end
113
+
114
+ #
115
+ # Evaluate the transaction proposal and obtain its result, without updating the ledger. This runs the transaction
116
+ # on a peer to obtain a transaction result, but does not submit the endorsed transaction to the orderer to be
117
+ # committed to the ledger.
118
+ #
119
+ # @param [Hash] options gRPC call options @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
120
+ #
121
+ # @return [String] The result returned by the transaction function
122
+ #
123
+ def evaluate(options = {})
124
+ sign
125
+
126
+ evaluate_response = client.evaluate(new_evaluate_request, options)
127
+ evaluate_response.result.payload
128
+ end
129
+
130
+ #
131
+ # Obtain endorsement for the transaction proposal from sufficient peers to allow it to be committed to the ledger.
132
+ #
133
+ # @param [Hash] options gRPC call options @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
134
+ #
135
+ # @return [Fabric::Transaction] An endorsed transaction that can be submitted to the ledger.
136
+ #
137
+ def endorse(options = {})
138
+ sign
139
+ endorse_response = client.endorse(new_endorse_request, options)
140
+
141
+ raise Fabric::Error, 'Missing transaction envelope' if endorse_response.prepared_transaction.nil?
142
+
143
+ prepared_transaction = new_prepared_transaction(endorse_response.prepared_transaction)
144
+
145
+ Fabric::Transaction.new(network, prepared_transaction)
146
+ end
147
+
148
+ #
149
+ # Generates an evaluate request from this proposal.
150
+ #
151
+ # @return [Gateway::EvaluateRequest] evaluation request with the current proposal
152
+ #
153
+ def new_evaluate_request
154
+ ::Gateway::EvaluateRequest.new(
155
+ channel_id: network_name,
156
+ proposed_transaction: signed_proposal,
157
+ target_organizations: proposed_transaction.endorsing_organizations
158
+ )
159
+ end
160
+
161
+ #
162
+ # Creates a new endorse request from this proposal.
163
+ #
164
+ # @return [Gateway::EndorseRequest] EndorseRequest protobuf message
165
+ #
166
+ def new_endorse_request
167
+ ::Gateway::EndorseRequest.new(
168
+ transaction_id: transaction_id,
169
+ channel_id: network_name,
170
+ proposed_transaction: signed_proposal,
171
+ endorsing_organizations: proposed_transaction.endorsing_organizations
172
+ )
173
+ end
174
+
175
+ #
176
+ # Creates a new prepared transaction from a transaction envelope.
177
+ #
178
+ # @param [Common::Envelope] envelope transaction envelope
179
+ #
180
+ # @return [Gateway::PreparedTransaction] prepared transaction protobuf message
181
+ #
182
+ def new_prepared_transaction(envelope)
183
+ ::Gateway::PreparedTransaction.new(
184
+ transaction_id: transaction_id,
185
+ envelope: envelope
186
+ )
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fabric
4
+ #
5
+ # Manages the instantiation and creation of the Gateway::ProposedTransaction Protobuf Message.
6
+ #
7
+ # Adapted from official fabric-gateway SDK ProposalBuilder and hyperledger-fabric-sdk:
8
+ # https://github.com/hyperledger/fabric-gateway/blob/1518e03ed3d6db1b6809e23e61a92744fd18e724/node/src/proposalbuilder.ts
9
+ # https://github.com/kirshin/hyperledger-fabric-sdk/blob/95a5a1a37001852312df25946e960a9ff149207e/lib/fabric/proposal.rb
10
+ class ProposedTransaction
11
+ attr_reader :contract,
12
+ :transaction_name,
13
+ :transient_data,
14
+ :arguments,
15
+ :proposed_transaction
16
+
17
+ # Specifies the set of organizations that will attempt to endorse the proposal.
18
+ # No other organizations' peers will be sent this proposal.
19
+ # This is usually used in conjunction with transientData for private data scenarios.
20
+ attr_reader :endorsing_organizations
21
+
22
+ # @!parse include Fabric::Accessors::Network
23
+ # @!parse include Fabric::Accessors::Gateway
24
+ include Fabric::Accessors::Contract
25
+
26
+ def initialize(contract, transaction_name, arguments: [], transient_data: {}, endorsing_organizations: [])
27
+ @contract = contract
28
+ @transaction_name = transaction_name
29
+ @arguments = arguments
30
+ @transient_data = transient_data
31
+ @endorsing_organizations = endorsing_organizations
32
+
33
+ generate_proposed_transaction
34
+ end
35
+
36
+ #
37
+ # Builds the proposed transaction protobuf message
38
+ #
39
+ # @return [Gateway::ProposedTransaction]
40
+ #
41
+ def generate_proposed_transaction
42
+ @proposed_transaction = ::Gateway::ProposedTransaction.new(
43
+ transaction_id: transaction_id,
44
+ proposal: signed_proposal,
45
+ endorsing_organizations: endorsing_organizations
46
+ )
47
+ end
48
+
49
+ def signed_proposal
50
+ @signed_proposal ||= Protos::SignedProposal.new(
51
+ proposal_bytes: proposal.to_proto
52
+ )
53
+ end
54
+
55
+ def proposal
56
+ @proposal ||= Protos::Proposal.new header: header.to_proto,
57
+ payload: chaincode_proposal_payload.to_proto
58
+ end
59
+
60
+ def header
61
+ Common::Header.new channel_header: channel_header.to_proto,
62
+ signature_header: signature_header.to_proto
63
+ end
64
+
65
+ def channel_header
66
+ Common::ChannelHeader.new type: Common::HeaderType::ENDORSER_TRANSACTION,
67
+ channel_id: network_name, tx_id: transaction_id,
68
+ extension: channel_header_extension.to_proto,
69
+ timestamp: timestamp, epoch: 0
70
+ # version: Constants::CHANNEL_HEADER_VERSION # official SDK does not send this.
71
+ end
72
+
73
+ def channel_header_extension
74
+ Protos::ChaincodeHeaderExtension.new chaincode_id: chaincode_id
75
+ end
76
+
77
+ def chaincode_id
78
+ Protos::ChaincodeID.new name: chaincode_name
79
+ end
80
+
81
+ def chaincode_proposal_payload
82
+ chaincode_input = Protos::ChaincodeInput.new args: [transaction_name] + arguments
83
+ chaincode_spec = Protos::ChaincodeSpec.new type: Protos::ChaincodeSpec::Type::NODE,
84
+ chaincode_id: chaincode_id,
85
+ input: chaincode_input
86
+ input = Protos::ChaincodeInvocationSpec.new chaincode_spec: chaincode_spec
87
+
88
+ Protos::ChaincodeProposalPayload.new input: input.to_proto, TransientMap: transient_data
89
+ end
90
+
91
+ #
92
+ # Returns the current timestamp
93
+ #
94
+ # @return [Google::Protobuf::Timestamp] gRPC timestamp
95
+ #
96
+ def timestamp
97
+ now = Time.now
98
+
99
+ @timestamp ||= Google::Protobuf::Timestamp.new seconds: now.to_i, nanos: now.nsec
100
+ end
101
+
102
+ #
103
+ # Generates a random nonce
104
+ #
105
+ # @return [String] random nonce
106
+ #
107
+ def nonce
108
+ @nonce ||= signer.crypto_suite.generate_nonce
109
+ end
110
+
111
+ #
112
+ # Generates a unique transaction ID for the transaction based on a random number and the signer
113
+ # or returns the existing transaction ID if it has already been generated.
114
+ #
115
+ # @return [String] transaction ID
116
+ #
117
+ def transaction_id
118
+ @transaction_id ||= signer.crypto_suite.hexdigest(nonce + signer.to_proto)
119
+ end
120
+
121
+ #
122
+ # Generates a SignatureHeader protobuf message from the signer and nonce
123
+ #
124
+ # @return [Common::SignatureHeader] signature header protobuf message instance
125
+ #
126
+ def signature_header
127
+ Common::SignatureHeader.new creator: signer.to_proto, nonce: nonce
128
+ end
129
+
130
+ # Dev note: if we have more classes that encapsulate protobuffer messages, consider
131
+ # creating an EncapsulatedPBMessage to hold the message and expose the following methods
132
+ # as common interface.
133
+
134
+ #
135
+ # Returns the protobuf message instance
136
+ #
137
+ # @return [Gateway::ProposedTransaction] protobuf message instance
138
+ #
139
+ def as_proto
140
+ proposed_transaction
141
+ end
142
+
143
+ #
144
+ # Returns the serialized Protobuf binary form of the proposed transaction
145
+ #
146
+ # @return [String] serialized Protobuf binary form of the proposed transaction
147
+ #
148
+ def to_proto
149
+ proposed_transaction.to_proto
150
+ end
151
+
152
+ #
153
+ # Returns the serialized JSON form of the proposed transaction
154
+ #
155
+ # @param [Hash] options JSON serialization options @see https://ruby-doc.org/stdlib-2.6.3/libdoc/json/rdoc/JSON.html#method-i-generate
156
+ #
157
+ # @return [String] serialized JSON form of the proposed transaction
158
+ #
159
+ def to_json(options = {})
160
+ proposed_transaction.to_json(options)
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fabric
4
+ #
5
+ # Status of a transaction that is to be committed to the ledger.
6
+ #
7
+ class Status
8
+ TRANSACTION_STATUSES = ::Protos::TxValidationCode.constants.map(&::Protos::TxValidationCode.method(:const_get))
9
+ .collect do |i|
10
+ [::Protos::TxValidationCode.lookup(i), i]
11
+ end.to_h
12
+
13
+ # @return [Integer] Block number in which the transaction committed.
14
+ attr_reader :block_number
15
+
16
+ # @return [Integer] Transaction status
17
+ attr_reader :code
18
+
19
+ # @return [Boolean] `true` if the transaction committed successfully; otherwise `false`.
20
+ attr_reader :successful
21
+
22
+ # @return [String] The ID of the transaction.
23
+ attr_reader :transaction_id
24
+
25
+ def initialize(transaction_id, block_number, code)
26
+ @transaction_id = transaction_id
27
+ @block_number = block_number
28
+ @code = code
29
+ @successful = @code == TRANSACTION_STATUSES[:VALID]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fabric
4
+ #
5
+ # Represents an endorsed transaction that can be submitted to the orderer for commit to the ledger,
6
+ # query the transaction results and its commit status.
7
+ #
8
+ class Transaction
9
+ attr_reader :network
10
+
11
+ include Fabric::Accessors::Network
12
+
13
+ # @return [Gateway::PreparedTransaction] Prepared Transaction
14
+ attr_reader :prepared_transaction
15
+
16
+ # @return [Fabric::Envelope]
17
+ attr_reader :envelope
18
+
19
+ #
20
+ # Creates a new Transaction instance.
21
+ #
22
+ # @param [Fabric::Network] network
23
+ # @param [Gateway::PreparedTransaction] prepared_transaction
24
+ #
25
+ def initialize(network, prepared_transaction)
26
+ @network = network
27
+ @prepared_transaction = prepared_transaction
28
+ @envelope = Envelope.new(prepared_transaction.envelope)
29
+ end
30
+
31
+ #
32
+ # Get the transaction result. This is obtained during the endorsement process when the transaction proposal is
33
+ # run on endorsing peers.
34
+ #
35
+ # @param [boolean] check_status set to true to raise exception if transaction has not yet been committed
36
+ #
37
+ # @return [String] Raw transaction result
38
+ #
39
+ def result(check_status: true)
40
+ raise Fabric::CommitError, status if check_status && !status.successful
41
+
42
+ envelope.result
43
+ end
44
+
45
+ #
46
+ # Returns the transaction ID from the prepared transaction.
47
+ #
48
+ # @return [String] transaction_id
49
+ #
50
+ def transaction_id
51
+ prepared_transaction.transaction_id
52
+ end
53
+
54
+ #
55
+ # Submit the transaction to the orderer to be committed to the ledger.
56
+ #
57
+ # @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
58
+ #
59
+ # @param [Hash] options gRPC call options
60
+ #
61
+ # @return [Fabric::Transaction] self
62
+ def submit(options = {})
63
+ sign_submit_request
64
+
65
+ client.submit(new_submit_request, options)
66
+
67
+ self
68
+ end
69
+
70
+ #
71
+ # Sign the transaction envelope.
72
+ #
73
+ # @return [void]
74
+ def sign_submit_request
75
+ return if submit_request_signed?
76
+
77
+ signature = signer.sign(envelope.payload_bytes)
78
+ self.submit_request_signature = signature
79
+ end
80
+
81
+ #
82
+ # Returns true if the transaction envelope has been signed.
83
+ #
84
+ # @return [Boolean] true if signed; false otherwise
85
+ #
86
+ def submit_request_signed?
87
+ @envelope.signed?
88
+ end
89
+
90
+ #
91
+ # Digest to be signed to support offline signing of the submit request
92
+ #
93
+ # @return [String] digest of the submit request
94
+ #
95
+ def submit_request_digest
96
+ envelope.payload_digest
97
+ end
98
+
99
+ #
100
+ # Sets the submit request signature. This is used to support offline signing of the submit request.
101
+ #
102
+ # @param [String] signature
103
+ #
104
+ # @return [void]
105
+ #
106
+ def submit_request_signature=(signature)
107
+ envelope.signature = signature
108
+ end
109
+
110
+ #
111
+ # Get status of the committed transaction. If the transaction has not yet committed, this method blocks until the
112
+ # commit occurs. If status is already queried, this returns status from cache and does not make additional queries.
113
+ #
114
+ # @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
115
+ #
116
+ # @param [Hash] options gRPC call options
117
+ #
118
+ # @return [Fabric::Status] status of the committed transaction
119
+ #
120
+ def status(options = {})
121
+ @status ||= query_status(options)
122
+ end
123
+
124
+ #
125
+ # Digest to be signed to support offline signing of the commit status request
126
+ #
127
+ # @return [String] digest of the commit status request
128
+ #
129
+ def status_request_digest
130
+ Fabric.crypto_suite.digest(signed_commit_status_request.request)
131
+ end
132
+
133
+ #
134
+ # Sets the status request signature. This is used to support offline signing of the commit status request.
135
+ #
136
+ # @param [String] signature
137
+ #
138
+ # @return [void]
139
+ #
140
+ def status_request_signature=(signature)
141
+ signed_commit_status_request.signature = signature
142
+ end
143
+
144
+ #
145
+ # Returns true if the signed commit status request has been signed.
146
+ #
147
+ # @return [Boolean] true if signed; false otherwise
148
+ #
149
+ def status_request_signed?
150
+ !signed_commit_status_request.signature.empty?
151
+ end
152
+
153
+ #
154
+ # Sign the signed commit status request
155
+ #
156
+ # @return [Fabric::Transaction] self
157
+ #
158
+ def sign_status_request
159
+ return if status_request_signed?
160
+
161
+ signature = signer.sign(signed_commit_status_request.request)
162
+ signed_commit_status_request.signature = signature
163
+
164
+ self
165
+ end
166
+
167
+ #
168
+ # Returns the current instance of the signed commit status request. Necessary so we can keep the state of the
169
+ # signature in the transaction object.
170
+ #
171
+ # @return [Gateway::SignedCommitStatusRequest] signed commit status request
172
+ #
173
+ def signed_commit_status_request
174
+ @signed_commit_status_request ||= new_signed_commit_status_request
175
+ end
176
+
177
+ private
178
+
179
+ #
180
+ # Actual status query call used by status method.
181
+ #
182
+ # @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
183
+ #
184
+ # @param [Hash] options gRPC call options
185
+ #
186
+ # @return [Fabric::Status] status of the committed transaction
187
+ #
188
+ def query_status(options = {})
189
+ sign_status_request
190
+
191
+ commit_status_response = client.commit_status(signed_commit_status_request, options)
192
+ new_status(commit_status_response)
193
+ end
194
+
195
+ #
196
+ # Generates a new signed commit status request
197
+ #
198
+ # @return [Gateway::SignedCommitStatusRequest] signed commit status request protobuf message
199
+ #
200
+ def new_signed_commit_status_request
201
+ ::Gateway::SignedCommitStatusRequest.new(
202
+ request: new_commit_status_request.to_proto
203
+ )
204
+ end
205
+
206
+ #
207
+ # Generates a new commit status request
208
+ #
209
+ # @return [Gateway::CommitStatusRequest] commit status request protobuf message
210
+ #
211
+ def new_commit_status_request
212
+ ::Gateway::CommitStatusRequest.new(
213
+ channel_id: network_name,
214
+ transaction_id: transaction_id,
215
+ identity: signer.to_proto
216
+ )
217
+ end
218
+
219
+ #
220
+ # Generates a new submit request.
221
+ #
222
+ # @return [Gateway::SubmitRequest] submit request protobuf message
223
+ #
224
+ def new_submit_request
225
+ ::Gateway::SubmitRequest.new(
226
+ transaction_id: transaction_id,
227
+ channel_id: network_name,
228
+ prepared_transaction: envelope.envelope
229
+ )
230
+ end
231
+
232
+ #
233
+ # New Status from CommitStatusResponse
234
+ #
235
+ # @param [Gateway::CommitStatusResponse] response commit status response
236
+ #
237
+ # @return [Fabric::Status] transaction status
238
+ #
239
+ def new_status(response)
240
+ Fabric::Status.new(
241
+ transaction_id,
242
+ response.block_number,
243
+ Fabric::Status::TRANSACTION_STATUSES[response.result]
244
+ )
245
+ end
246
+ end
247
+ end
@@ -1,10 +1,35 @@
1
- require "fabric/gateway/version"
2
- require "gateway/gateway_pb"
3
- require "gateway/gateway_services_pb"
1
+ # frozen_string_literal: true
4
2
 
5
3
  module Fabric
6
- module Gateway
7
- class Error < StandardError; end
8
- # Your code goes here...
4
+ #
5
+ # Gateway represents the connection of a specific client identity to a Fabric Gateway.
6
+ #
7
+ class Gateway
8
+ attr_reader :signer, :client
9
+
10
+ #
11
+ # Initialize a new Gateway
12
+ #
13
+ # @param [Fabric::Identity] signer identity utilized to sign transactions
14
+ # @param [Fabric::Client] client Gateway Client
15
+ #
16
+ def initialize(signer, client)
17
+ raise InvalidArgument, 'signer must be Fabric::Identity' unless signer.is_a? Fabric::Identity
18
+ raise InvalidArgument, 'client must be Fabric::Client' unless client.is_a? Fabric::Client
19
+
20
+ @signer = signer
21
+ @client = client
22
+ end
23
+
24
+ #
25
+ # Initialize new network from the Gateway
26
+ #
27
+ # @param [string] name channel name
28
+ #
29
+ # @return [Fabric::Network] returns a new network
30
+ #
31
+ def new_network(name)
32
+ Network.new(self, name)
33
+ end
9
34
  end
10
35
  end