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.
- checksums.yaml +4 -4
- data/.editorconfig +3 -0
- data/.github/workflows/codeql-analysis.yml +71 -0
- data/.github/workflows/rspec.yml +37 -0
- data/.github/workflows/rubocop.yml +28 -0
- data/.github/workflows/todo.yml +10 -0
- data/.github/workflows/yardoc.yml +28 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +23 -0
- data/.ruby-version +1 -0
- data/.vscode/settings.json +7 -0
- data/.yardopts +8 -0
- data/CODE_OF_CONDUCT.md +105 -46
- data/Gemfile +5 -3
- data/LICENSE.txt +1 -1
- data/README.md +123 -12
- data/Rakefile +6 -3
- data/bin/console +4 -3
- data/bin/regenerate +1 -0
- data/bin/release +5 -0
- data/fabric-gateway.gemspec +31 -17
- data/lib/fabric/accessors/contract.rb +51 -0
- data/lib/fabric/accessors/gateway.rb +33 -0
- data/lib/fabric/accessors/network.rb +40 -0
- data/lib/fabric/client.rb +199 -0
- data/lib/fabric/constants.rb +8 -0
- data/lib/fabric/contract.rb +178 -0
- data/lib/fabric/ec_crypto_suite.rb +199 -0
- data/lib/fabric/entities/chaincode_events_requests.rb +166 -0
- data/lib/fabric/entities/envelope.rb +158 -0
- data/lib/fabric/entities/identity.rb +87 -0
- data/lib/fabric/entities/proposal.rb +189 -0
- data/lib/fabric/entities/proposed_transaction.rb +163 -0
- data/lib/fabric/entities/status.rb +32 -0
- data/lib/fabric/entities/transaction.rb +247 -0
- data/lib/fabric/gateway.rb +31 -6
- data/lib/fabric/network.rb +70 -0
- data/lib/fabric/version.rb +5 -0
- data/lib/fabric.rb +59 -0
- data/lib/msp/identities_pb.rb +25 -0
- metadata +162 -13
- data/Gemfile.lock +0 -42
- data/lib/fabric/gateway/version.rb +0 -5
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'fabric'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +11,5 @@ require "fabric/gateway"
|
|
10
11
|
# require "pry"
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start(__FILE__)
|
data/bin/regenerate
CHANGED
@@ -16,3 +16,4 @@ grpc_tools_ruby_protoc -I ./fabric-protos --ruby_out=./lib --grpc_out=./lib ./fa
|
|
16
16
|
grpc_tools_ruby_protoc -I ./fabric-protos --ruby_out=./lib --grpc_out=./lib ./fabric-protos/orderer/ab.proto
|
17
17
|
grpc_tools_ruby_protoc -I ./fabric-protos --ruby_out=./lib --grpc_out=./lib ./fabric-protos/gossip/message.proto
|
18
18
|
grpc_tools_ruby_protoc -I ./fabric-protos --ruby_out=./lib --grpc_out=./lib ./fabric-protos/msp/msp_principal.proto
|
19
|
+
grpc_tools_ruby_protoc -I ./fabric-protos --ruby_out=./lib --grpc_out=./lib ./fabric-protos/msp/identities.proto
|
data/bin/release
ADDED
data/fabric-gateway.gemspec
CHANGED
@@ -1,31 +1,45 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/fabric/version'
|
2
4
|
|
3
5
|
Gem::Specification.new do |spec|
|
4
|
-
spec.name =
|
5
|
-
spec.version = Fabric::
|
6
|
-
spec.authors = [
|
7
|
-
spec.email = [
|
6
|
+
spec.name = 'fabric-gateway'
|
7
|
+
spec.version = Fabric::VERSION
|
8
|
+
spec.authors = ['Jonathan Chan']
|
9
|
+
spec.email = ['jonathan.chan@ethicalidentity.com']
|
8
10
|
|
9
|
-
spec.summary =
|
10
|
-
spec.description =
|
11
|
-
spec.homepage =
|
12
|
-
spec.license =
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(
|
11
|
+
spec.summary = 'Hyperledger Fabric Gateway SDK'
|
12
|
+
spec.description = 'Ruby port of the Hyperledger Fabric Gateway SDK'
|
13
|
+
spec.homepage = 'https://github.com/ethicalidentity/fabric-gateway-ruby'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
|
14
16
|
|
15
|
-
spec.metadata[
|
17
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
16
18
|
|
17
|
-
spec.metadata[
|
18
|
-
spec.metadata[
|
19
|
-
spec.metadata[
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/ethicalidentity/fabric-gateway-ruby'
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/EthicalIdentity/fabric-gateway-ruby/blob/master/CHANGELOG.md'
|
20
22
|
|
21
23
|
# Specify which files should be added to the gem when it is released.
|
22
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
-
spec.files
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
26
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
27
|
end
|
26
|
-
spec.bindir =
|
28
|
+
spec.bindir = 'exe'
|
27
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
-
spec.require_paths = [
|
30
|
+
spec.require_paths = ['lib']
|
29
31
|
spec.add_dependency('google-protobuf', '>= 3.19.1')
|
30
32
|
spec.add_dependency('grpc', '~> 1.42')
|
33
|
+
spec.add_development_dependency('codecov', '~> 0.6.0')
|
34
|
+
spec.add_development_dependency('factory_bot', '~> 6.2.0')
|
35
|
+
spec.add_development_dependency('grpc-tools', '~> 1.42')
|
36
|
+
spec.add_development_dependency('rake-notes', '~> 0.2.0')
|
37
|
+
spec.add_development_dependency('rubocop', '~> 1.23.0')
|
38
|
+
spec.add_development_dependency('rubocop-rspec', '~> 2.6.0')
|
39
|
+
spec.add_development_dependency('simplecov', '~> 0.21.2')
|
40
|
+
spec.add_development_dependency('timecop', '~> 0.9.4')
|
41
|
+
spec.add_development_dependency('yard', '~> 0.9.27')
|
42
|
+
spec.metadata = {
|
43
|
+
'rubygems_mfa_required' => 'true'
|
44
|
+
}
|
31
45
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fabric
|
4
|
+
module Accessors
|
5
|
+
#
|
6
|
+
# Add accessor methods to the given class.
|
7
|
+
#
|
8
|
+
# Usage: make sure the class has a contract accessor method
|
9
|
+
# and then `include Fabric::Accessors::Contract`
|
10
|
+
#
|
11
|
+
module Contract
|
12
|
+
# @!visibility private
|
13
|
+
def self.included(base)
|
14
|
+
base.send :include, Fabric::Accessors::Network
|
15
|
+
end
|
16
|
+
|
17
|
+
# @!parse include Fabric::Accessors::Network
|
18
|
+
# @!parse include Fabric::Accessors::Gateway
|
19
|
+
|
20
|
+
#
|
21
|
+
# Returns the network instance
|
22
|
+
#
|
23
|
+
# @return [Fabric::Network] network
|
24
|
+
# @!parse attr_reader :network
|
25
|
+
#
|
26
|
+
def network
|
27
|
+
contract.network
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Returns the contract name
|
32
|
+
#
|
33
|
+
# @return [String] contract name
|
34
|
+
# @!parse attr_reader :contract_name
|
35
|
+
#
|
36
|
+
def contract_name
|
37
|
+
contract.contract_name
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Returns the chaincode name
|
42
|
+
#
|
43
|
+
# @return [String] chaincode name
|
44
|
+
# @!parse attr_reader :chaincode_name
|
45
|
+
#
|
46
|
+
def chaincode_name
|
47
|
+
contract.chaincode_name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fabric
|
4
|
+
module Accessors
|
5
|
+
#
|
6
|
+
# Add accessor methods to the given class.
|
7
|
+
#
|
8
|
+
# Usage: make sure the class has a gateway accessor method
|
9
|
+
# and then `include Fabric::Accessors::Gateway`
|
10
|
+
#
|
11
|
+
module Gateway
|
12
|
+
#
|
13
|
+
# Returns the client instance
|
14
|
+
#
|
15
|
+
# @return [Fabric::Client] client
|
16
|
+
# @!parse attr_reader :client
|
17
|
+
#
|
18
|
+
def client
|
19
|
+
gateway.client
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Returns the signer identity instance
|
24
|
+
#
|
25
|
+
# @return [Fabric::Identity] signer
|
26
|
+
# @!parse attr_reader :signer
|
27
|
+
#
|
28
|
+
def signer
|
29
|
+
gateway.signer
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fabric
|
4
|
+
module Accessors
|
5
|
+
#
|
6
|
+
# Add accessor methods to the given class.
|
7
|
+
#
|
8
|
+
# Usage: make sure the class has a network accessor method
|
9
|
+
# and then `include Fabric::Accessors::Network`
|
10
|
+
#
|
11
|
+
module Network
|
12
|
+
# @!visibility private
|
13
|
+
def self.included(base)
|
14
|
+
base.send :include, Fabric::Accessors::Gateway
|
15
|
+
end
|
16
|
+
|
17
|
+
# @!parse include Fabric::Accessors::Gateway
|
18
|
+
|
19
|
+
#
|
20
|
+
# Returns the gateway instance
|
21
|
+
#
|
22
|
+
# @return [Fabric::Gateway] gateway
|
23
|
+
# @!parse attr_reader :gateway
|
24
|
+
#
|
25
|
+
def gateway
|
26
|
+
network.gateway
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Network name or the channel name or channel id
|
31
|
+
#
|
32
|
+
# @return [String] network name
|
33
|
+
# @!parse attr_reader :network_name
|
34
|
+
#
|
35
|
+
def network_name
|
36
|
+
network.name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fabric
|
4
|
+
#
|
5
|
+
# Gateway Client represents the connection to a Hyperledger Fabric Gateway.
|
6
|
+
#
|
7
|
+
class Client
|
8
|
+
attr_reader :grpc_client, :default_call_options
|
9
|
+
|
10
|
+
#
|
11
|
+
# Initializes a client
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# @overload initialize(grpc_client: client, default_call_options: {}, **client_opts)
|
15
|
+
# Initializes a client from a gRPC Gateway client stub
|
16
|
+
# @param [Gateway::Gateway::Stub] grpc_client grpc gateway client stub
|
17
|
+
# @param [Hash] default_call_options call options to use by default for different operations
|
18
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response Keyword Argument call options for
|
19
|
+
# *_options default_call_options
|
20
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:initialize Keyword arguments for **client_opts
|
21
|
+
# @option default_call_options [Hash] :endorse_options default options for endorse call
|
22
|
+
# @option default_call_options [Hash] :evaluate_options default options for evaluate call
|
23
|
+
# @option default_call_options [Hash] :submit_options default options for submit call
|
24
|
+
# @option default_call_options [Hash] :commit_status_options default options for commit_status call
|
25
|
+
# @option default_call_options [Hash] :chaincode_events_options default options for chaincode_events call
|
26
|
+
# @param [Hash] **client_opts client initialization options
|
27
|
+
# @overload initialize(host: host, creds: creds, default_call_options: {}, **client_opts)
|
28
|
+
# Instantiates a new gRPC Gateway client stub from the parameters
|
29
|
+
# @param [string] host hostname and port of the gateway
|
30
|
+
# @param [GRPC::Core::ChannelCredentials|GRPC::Core::XdsChannelCredentials|Symbol] creds channel credentials
|
31
|
+
# (usually the CA certificate)
|
32
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response Keyword Argument call options for
|
33
|
+
# *_options default_call_options
|
34
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:initialize Keyword arguments for **client_opts
|
35
|
+
# @option default_call_options [Hash] :endorse_options default options for endorse call
|
36
|
+
# @option default_call_options [Hash] :evaluate_options default options for evaluate call
|
37
|
+
# @option default_call_options [Hash] :submit_options default options for submit call
|
38
|
+
# @option default_call_options [Hash] :commit_status_options default options for commit_status call
|
39
|
+
# @option default_call_options [Hash] :chaincode_events_options default options for chaincode_events call
|
40
|
+
# @param [Hash] **client_opts client initialization options
|
41
|
+
#
|
42
|
+
def initialize(grpc_client: nil, host: nil, creds: nil, default_call_options: {}, **client_opts)
|
43
|
+
if grpc_client
|
44
|
+
init_stub grpc_client
|
45
|
+
elsif host && creds
|
46
|
+
init_grpc_args(host, creds, **client_opts)
|
47
|
+
else
|
48
|
+
raise InvalidArgument, 'Must pass a Gateway::Gateway::Stub or <host>, <creds>, <client_opts>'
|
49
|
+
end
|
50
|
+
init_call_options(default_call_options)
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Submits an evaluate_request to the gateway to be evaluted.
|
55
|
+
#
|
56
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response Call options for options parameter
|
57
|
+
# @param [Gateway::EvaluateRequest] evaluate_request
|
58
|
+
# @param [Hash] options gRPC call options (merged with default_call_options from initializer)
|
59
|
+
#
|
60
|
+
# @return [Gateway::EvaluateResponse] evaluate_response
|
61
|
+
#
|
62
|
+
def evaluate(evaluate_request, options = {})
|
63
|
+
@grpc_client.evaluate(evaluate_request, @default_call_options[:evaluate_options].merge(options))
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Submits an endorse_request to the gateway to be evaluted.
|
68
|
+
#
|
69
|
+
# @param [Gateway::EndorseRequest] endorse_request
|
70
|
+
# @param [Hash] options gRPC call options (merged with default options) @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
|
71
|
+
#
|
72
|
+
# @return [Gateway::EndorseResponse] endorse_response
|
73
|
+
#
|
74
|
+
def endorse(endorse_request, options = {})
|
75
|
+
@grpc_client.endorse(endorse_request, @default_call_options[:endorse_options].merge(options))
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Submits an submit_request to the gateway to be evaluted.
|
80
|
+
#
|
81
|
+
# @param [Gateway::SubmitRequest] submit_request
|
82
|
+
# @param [Hash] options gRPC call options (merged with default options) @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
|
83
|
+
#
|
84
|
+
# @return [Gateway::SubmitResponse] submit_response
|
85
|
+
#
|
86
|
+
def submit(submit_request, options = {})
|
87
|
+
@grpc_client.submit(submit_request, @default_call_options[:submit_options].merge(options))
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Submits an commit_status_request to the gateway to be evaluted.
|
92
|
+
#
|
93
|
+
# @param [Gateway::CommitStatusRequest] commit_status_request
|
94
|
+
# @param [Hash] options gRPC call options (merged with default options) @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:request_response
|
95
|
+
#
|
96
|
+
# Returns an enum or if you pass a block, use the block.
|
97
|
+
# @return [Gateway::CommitStatusResponse] commit_status_response
|
98
|
+
#
|
99
|
+
def commit_status(commit_status_request, options = {})
|
100
|
+
@grpc_client.commit_status(commit_status_request, @default_call_options[:commit_status_options].merge(options))
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Subscribe to chaincode events
|
105
|
+
#
|
106
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:server_streamer GRPC::ClientStub#server_streamer
|
107
|
+
# - gRPC Underlying Call Reference
|
108
|
+
#
|
109
|
+
#
|
110
|
+
# @overload chaincode_events(chaincode_events_request)
|
111
|
+
# @example Utilizing Blocking Enumerator
|
112
|
+
# call = client.chaincode_events(chaincode_events_request)
|
113
|
+
# call.each do |event|
|
114
|
+
# pp event
|
115
|
+
# end
|
116
|
+
# @param [Gateway::ChaincodeEventsRequest] chaincode_events_request
|
117
|
+
# @param [Hash] options gRPC call options (merged with default options)
|
118
|
+
# @return [Enumerator] enumerator with Gateway::ChaincodeEventsResponse objects
|
119
|
+
# @overload chaincode_events(chaincode_events_request)
|
120
|
+
# @example Utilizing a blocking block
|
121
|
+
# client.chaincode_events(chaincode_events_request) do |event|
|
122
|
+
# pp event
|
123
|
+
# end
|
124
|
+
# @param [Gateway::ChaincodeEventsRequest] chaincode_events_request
|
125
|
+
# @param [Hash] options gRPC call options (merged with default options)
|
126
|
+
# @yield [event] Blocking call that yields Gateway::ChaincodeEventsResponse objects when received from the server
|
127
|
+
# @yieldparam event [Gateway::ChaincodeEventsResponse] chaincode event
|
128
|
+
# @return [nil]
|
129
|
+
# @overload chaincode_events(chaincode_events_request, {return_op: true})
|
130
|
+
# @example Utilizing an operation control object and a enumerator
|
131
|
+
# op = client.chaincode_events(chaincode_events_request, {return_op: true})
|
132
|
+
#
|
133
|
+
# t = Thread.new do
|
134
|
+
# call = op.execute
|
135
|
+
# call.each do |event|
|
136
|
+
# pp event
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# op.status
|
141
|
+
# op.cancelled?
|
142
|
+
# op.cancel
|
143
|
+
# @param [Gateway::ChaincodeEventsRequest] chaincode_events_request
|
144
|
+
# @param [Hash] options gRPC call options (merged with default options)
|
145
|
+
# @return [GRPC::ActiveCall::Operation]
|
146
|
+
# @overload chaincode_events(chaincode_events_request, {return_op: true})
|
147
|
+
# @example Utilizing an operation control object and a block
|
148
|
+
# op = client.chaincode_events(chaincode_events_request, {return_op: true}) do |event|
|
149
|
+
# pp event
|
150
|
+
# end
|
151
|
+
#
|
152
|
+
# t = Thread.new do
|
153
|
+
# call = op.execute
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# op.status
|
157
|
+
# op.cancelled?
|
158
|
+
# op.cancel
|
159
|
+
# @param [Gateway::ChaincodeEventsRequest] chaincode_events_request
|
160
|
+
# @param [Hash] options gRPC call options (merged with default options)
|
161
|
+
# @yield [event] Blocking call that yields Gateway::ChaincodeEventsResponse objects when received from the server
|
162
|
+
# @yieldparam event [Gateway::ChaincodeEventsResponse] chaincode event
|
163
|
+
# @return [GRPC::ActiveCall::Operation]
|
164
|
+
#
|
165
|
+
def chaincode_events(chaincode_events_request, options = {}, &block)
|
166
|
+
@grpc_client.chaincode_events(chaincode_events_request,
|
167
|
+
@default_call_options[:chaincode_events_options].merge(options), &block)
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def init_stub(stub)
|
173
|
+
unless stub.is_a? ::Gateway::Gateway::Stub
|
174
|
+
raise InvalidArgument, 'Must pass a Gateway::Gateway::Stub or <host>, <creds>, <client_opts>'
|
175
|
+
end
|
176
|
+
|
177
|
+
@grpc_client = stub
|
178
|
+
end
|
179
|
+
|
180
|
+
def init_grpc_args(host, creds, **client_opts)
|
181
|
+
unless creds.is_a?(GRPC::Core::ChannelCredentials) ||
|
182
|
+
creds.is_a?(GRPC::Core::XdsChannelCredentials) ||
|
183
|
+
creds.is_a?(Symbol)
|
184
|
+
raise InvalidArgument, 'creds is not a ChannelCredentials, XdsChannelCredentials, or Symbol'
|
185
|
+
end
|
186
|
+
|
187
|
+
@grpc_client = ::Gateway::Gateway::Stub.new(host, creds, **client_opts)
|
188
|
+
end
|
189
|
+
|
190
|
+
def init_call_options(call_options)
|
191
|
+
@default_call_options = call_options
|
192
|
+
@default_call_options[:endorse_options] ||= {}
|
193
|
+
@default_call_options[:evaluate_options] ||= {}
|
194
|
+
@default_call_options[:submit_options] ||= {}
|
195
|
+
@default_call_options[:commit_status_options] ||= {}
|
196
|
+
@default_call_options[:chaincode_events_options] ||= {}
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fabric
|
4
|
+
#
|
5
|
+
# Contract represents a smart contract, and allows applications to:
|
6
|
+
#
|
7
|
+
# - Evaluate transactions that query state from the ledger using the EvaluateTransaction() method.
|
8
|
+
#
|
9
|
+
# - Submit transactions that store state to the ledger using the SubmitTransaction() method.
|
10
|
+
#
|
11
|
+
# For more complex transaction invocations, such as including transient data, transactions can be evaluated or
|
12
|
+
# submitted using the Evaluate() or Submit() methods respectively. The result of a submitted transaction can be
|
13
|
+
# accessed prior to its commit to the ledger using SubmitAsync().
|
14
|
+
#
|
15
|
+
# By default, proposal, transaction and commit status messages will be signed using the signing implementation
|
16
|
+
# specified when connecting the Gateway. In cases where an external client holds the signing credentials, a signing
|
17
|
+
# implementation can be omitted when connecting the Gateway and off-line signing can be carried out by:
|
18
|
+
#
|
19
|
+
# 1. Returning the serialized proposal, transaction or commit status along with its digest to the client for
|
20
|
+
# them to generate a signature.
|
21
|
+
#
|
22
|
+
# 2. With the serialized message and signature received from the client to create a signed proposal, transaction or
|
23
|
+
# commit using the Gateway's NewSignedProposal(), NewSignedTransaction() or NewSignedCommit() methods respectively.
|
24
|
+
#
|
25
|
+
class Contract
|
26
|
+
attr_reader :network, :chaincode_name, :contract_name
|
27
|
+
|
28
|
+
# @!parse include Fabric::Accessors::Network
|
29
|
+
# @!parse include Fabric::Accessors::Gateway
|
30
|
+
include Fabric::Accessors::Network
|
31
|
+
|
32
|
+
def initialize(network, chaincode_name, contract_name = '')
|
33
|
+
@network = network
|
34
|
+
@chaincode_name = chaincode_name
|
35
|
+
@contract_name = contract_name
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Evaluate a transaction function and return its results. A transaction proposal will be evaluated on endorsing
|
40
|
+
# peers but the transaction will not be sent to the ordering service and so will not be committed to the ledger.
|
41
|
+
# This can be used for querying the world state.
|
42
|
+
#
|
43
|
+
# @param [String] transaction_name
|
44
|
+
# @param [Array] arguments array of arguments to pass to the transaction
|
45
|
+
#
|
46
|
+
# @return [String] raw payload of the transaction response
|
47
|
+
#
|
48
|
+
def evaluate_transaction(transaction_name, arguments = [])
|
49
|
+
evaluate(transaction_name, { arguments: arguments })
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Submit a transaction to the ledger and return its result only after it is committed to the ledger. The
|
54
|
+
# transaction function will be evaluated on endorsing peers and then submitted to the ordering service to be
|
55
|
+
# committed to the ledger.
|
56
|
+
#
|
57
|
+
#
|
58
|
+
# @param [String] transaction_name
|
59
|
+
# @param [Array] arguments array of arguments to pass to the transaction
|
60
|
+
#
|
61
|
+
# @return [String] raw payload of the transaction response
|
62
|
+
#
|
63
|
+
def submit_transaction(transaction_name, arguments = [])
|
64
|
+
submit(transaction_name, { arguments: arguments })
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Evaluate a transaction function and return its result. This method provides greater control over the transaction
|
69
|
+
# proposal content and the endorsing peers on which it is evaluated. This allows transaction functions to be
|
70
|
+
# evaluated where the proposal must include transient data, or that will access ledger data with key-based
|
71
|
+
# endorsement policies.
|
72
|
+
#
|
73
|
+
# @param [String] transaction_name
|
74
|
+
# @param [Hash] proposal_options
|
75
|
+
# @option proposal_options [Array] :arguments array of arguments to pass to the transaction
|
76
|
+
# @option proposal_options [Hash] :transient_data Private data passed to the transaction function but not recorded
|
77
|
+
# on the ledger.
|
78
|
+
# @option proposal_options [Array] :endorsing_organizations Specifies the set of organizations that will attempt to
|
79
|
+
# endorse the proposal.
|
80
|
+
#
|
81
|
+
# @return [String] Raw evaluation response payload
|
82
|
+
#
|
83
|
+
def evaluate(transaction_name, proposal_options = {})
|
84
|
+
new_proposal(transaction_name, **proposal_options).evaluate
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Submit a transaction to the ledger and return its result only after it is committed to the ledger. The
|
89
|
+
# transaction function will be evaluated on endorsing peers and then submitted to the ordering service to be
|
90
|
+
# committed to the ledger.
|
91
|
+
#
|
92
|
+
# @param [String] transaction_name
|
93
|
+
# @param [Hash] proposal_options
|
94
|
+
# @option proposal_options [Array] :arguments array of arguments to pass to the transaction
|
95
|
+
# @option proposal_options [Hash] :transient_data Private data passed to the transaction function but not recorded
|
96
|
+
# on the ledger.
|
97
|
+
# @option proposal_options [Array] :endorsing_organizations Specifies the set of organizations that will attempt to
|
98
|
+
# endorse the proposal.
|
99
|
+
#
|
100
|
+
# @return [String] Raw evaluation response payload
|
101
|
+
#
|
102
|
+
def submit(transaction_name, proposal_options = {})
|
103
|
+
transaction = new_proposal(transaction_name, **proposal_options).endorse
|
104
|
+
transaction.submit
|
105
|
+
|
106
|
+
transaction.result
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# @todo unimplemented, not sure if this can be implemented because
|
111
|
+
# the official grpc ruby client does not support non-blocking async
|
112
|
+
# calls (https://github.com/grpc/grpc/issues/10973)
|
113
|
+
#
|
114
|
+
# not 100% sure if grpc support is necessary for this.
|
115
|
+
#
|
116
|
+
def submit_async
|
117
|
+
raise NotYetImplemented
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Get chaincode events emitted by transaction functions of the chaincode.
|
122
|
+
#
|
123
|
+
# @see Fabric::Client#chaincode_events Fabric::Client#chaincode_events - explanation of the different return types
|
124
|
+
# and example usage.
|
125
|
+
# @see https://www.rubydoc.info/gems/grpc/GRPC%2FClientStub:server_streamer Call options for options parameter
|
126
|
+
#
|
127
|
+
# @param [Integer] start_block Block number at which to start reading chaincode events.
|
128
|
+
# @param [Hash] call_options gRPC call options (merged with default_call_options from initializer)
|
129
|
+
# @yield [chaincode_event] loops through the chaincode events
|
130
|
+
# @yieldparam [Gateway::ChaincodeEventsResponse] chaincode_event the chaincode event
|
131
|
+
#
|
132
|
+
# @return [Enumerator|GRPC::ActiveCall::Operation|nil] Dependent on parameters passed;
|
133
|
+
# please see Fabric::Client#get_chaincode_events
|
134
|
+
#
|
135
|
+
def chaincode_events(start_block: nil, call_options: {}, &block)
|
136
|
+
network.chaincode_events(
|
137
|
+
self,
|
138
|
+
start_block: start_block,
|
139
|
+
call_options: call_options,
|
140
|
+
&block
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Creates a transaction proposal that can be evaluated or endorsed. Supports off-line signing flow.
|
146
|
+
#
|
147
|
+
# @param [String] transaction_name transaction name (first argument unshifted into the argument array)
|
148
|
+
# @param [Array<String>] arguments array of arguments to pass to the transaction
|
149
|
+
# @param [Hash] transient_data Private data passed to the transaction function but not recorded on the ledger.
|
150
|
+
# @param [Array] endorsing_organizations Specifies the set of organizations that will attempt to endorse the
|
151
|
+
# proposal.
|
152
|
+
#
|
153
|
+
# @return [Fabric::Proposal] signed unexecuted proposal
|
154
|
+
#
|
155
|
+
def new_proposal(transaction_name, arguments: [], transient_data: {}, endorsing_organizations: [])
|
156
|
+
proposed_transaction = ProposedTransaction.new(
|
157
|
+
self,
|
158
|
+
qualified_transaction_name(transaction_name),
|
159
|
+
arguments: arguments,
|
160
|
+
transient_data: transient_data,
|
161
|
+
endorsing_organizations: endorsing_organizations
|
162
|
+
)
|
163
|
+
Proposal.new(proposed_transaction)
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Generates the qualified transaction name for the contract. (prepends the contract name to the transaction name if
|
168
|
+
# contract name is set)
|
169
|
+
#
|
170
|
+
# @param [string] transaction_name
|
171
|
+
#
|
172
|
+
# @return [string] qualified transaction name
|
173
|
+
#
|
174
|
+
def qualified_transaction_name(transaction_name)
|
175
|
+
contract_name.nil? || contract_name.empty? ? transaction_name : "#{contract_name}:#{transaction_name}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|