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
@@ -0,0 +1,145 @@
1
+ require 'openssl'
2
+
3
+ module Fabric
4
+ class CryptoSuite
5
+ DEFAULT_KEY_SIZE = 256
6
+ DEFAULT_DIGEST_ALGORITHM = 'SHA256'.freeze
7
+ DEFAULT_AES_KEY_SIZE = 128
8
+
9
+ EC_CURVES = { 256 => 'prime256v1', 384 => 'secp384r1' }.freeze
10
+
11
+ CIPHER = 'aes-256-cbc'.freeze
12
+
13
+ attr_reader :key_size, :digest_algorithm, :digest, :curve, :cipher
14
+
15
+ def initialize(opts = {})
16
+ @key_size = opts[:key_size] || DEFAULT_KEY_SIZE
17
+ @digest_algorithm = opts[:digest_algorithm] || DEFAULT_DIGEST_ALGORITHM
18
+ @digest = OpenSSL::Digest.new digest_algorithm
19
+ @curve = EC_CURVES[key_size]
20
+ @cipher = opts[:cipher] || CIPHER
21
+ end
22
+
23
+ def sign(private_key, message)
24
+ digest = digest message
25
+ key = pkey_from_private_key private_key
26
+ signature = key.dsa_sign_asn1 digest
27
+ sequence = OpenSSL::ASN1.decode signature
28
+ sequence = prevent_malleability sequence, key.group.order
29
+
30
+ sequence.to_der
31
+ end
32
+
33
+ def generate_private_key
34
+ key = OpenSSL::PKey::EC.new curve
35
+ key.generate_key!
36
+
37
+ key.private_key.to_i.to_s(16).downcase
38
+ end
39
+
40
+ def generate_csr(private_key, attrs = [])
41
+ key = pkey_from_private_key private_key
42
+
43
+ req = OpenSSL::X509::Request.new
44
+ req.public_key = key
45
+ req.subject = OpenSSL::X509::Name.new attrs
46
+ req.sign key, @digest
47
+
48
+ req
49
+ end
50
+
51
+ def generate_nonce(length = 24)
52
+ OpenSSL::Random.random_bytes length
53
+ end
54
+
55
+ def hexdigest(message)
56
+ @digest.hexdigest message
57
+ end
58
+
59
+ def digest(message)
60
+ @digest.digest message
61
+ end
62
+
63
+ def encode_hex(bytes)
64
+ bytes.unpack('H*').first
65
+ end
66
+
67
+ def decode_hex(string)
68
+ [string].pack('H*')
69
+ end
70
+
71
+ def keccak256(bytes)
72
+ Digest::SHA3.new(256).digest bytes
73
+ end
74
+
75
+ def restore_public_key(private_key)
76
+ private_bn = OpenSSL::BN.new private_key, 16
77
+ group = OpenSSL::PKey::EC::Group.new curve
78
+ public_bn = group.generator.mul(private_bn).to_bn
79
+ public_bn = OpenSSL::PKey::EC::Point.new(group, public_bn).to_bn
80
+
81
+ public_bn.to_s(16).downcase
82
+ end
83
+
84
+ def address_from_public_key(public_key)
85
+ bytes = decode_hex public_key
86
+ address_bytes = keccak256(bytes[1..-1])[-20..-1]
87
+
88
+ encode_hex address_bytes
89
+ end
90
+
91
+ def build_shared_key(private_key, public_key)
92
+ pkey = pkey_from_private_key private_key
93
+ public_bn = OpenSSL::BN.new public_key, 16
94
+ group = OpenSSL::PKey::EC::Group.new curve
95
+ public_point = OpenSSL::PKey::EC::Point.new group, public_bn
96
+
97
+ encode_hex pkey.dh_compute_key(public_point)
98
+ end
99
+
100
+ def encrypt(secret, data)
101
+ aes = OpenSSL::Cipher.new cipher
102
+ aes.encrypt
103
+ aes.key = decode_hex(secret)
104
+ iv = aes.random_iv
105
+ aes.iv = iv
106
+
107
+ Base64.strict_encode64(iv + aes.update(data) + aes.final)
108
+ end
109
+
110
+ def decrypt(secret, data)
111
+ return unless data
112
+
113
+ encrypted_data = Base64.strict_decode64 data
114
+ aes = OpenSSL::Cipher.new cipher
115
+ aes.decrypt
116
+ aes.key = decode_hex(secret)
117
+ aes.iv = encrypted_data[0..15]
118
+ encrypted_data = encrypted_data[16..-1]
119
+
120
+ aes.update(encrypted_data) + aes.final
121
+ end
122
+
123
+ private
124
+
125
+ def pkey_from_private_key(private_key)
126
+ public_key = restore_public_key private_key
127
+ key = OpenSSL::PKey::EC.new curve
128
+ key.private_key = OpenSSL::BN.new private_key, 16
129
+ key.public_key = OpenSSL::PKey::EC::Point.new key.group,
130
+ OpenSSL::BN.new(public_key, 16)
131
+
132
+ key
133
+ end
134
+
135
+ def prevent_malleability(sequence, order)
136
+ half_order = order >> 1
137
+
138
+ if (half_key = sequence.value[1].value) > half_order
139
+ sequence.value[1].value = order - half_key
140
+ end
141
+
142
+ sequence
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,26 @@
1
+ module Fabric
2
+ class EnumeratorQueue
3
+ extend Forwardable
4
+ def_delegators :@q, :push
5
+ def_delegators :@q, :size
6
+
7
+ def initialize(sentinel)
8
+ @q = Queue.new
9
+ @sentinel = sentinel
10
+ end
11
+
12
+ def each
13
+ return enum_for(:each) unless block_given?
14
+
15
+ loop do
16
+ r = @q.pop
17
+
18
+ break if r.equal?(@sentinel)
19
+
20
+ raise r if r.is_a? Exception
21
+
22
+ yield r
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,52 @@
1
+ module Fabric
2
+ class ErrorFactory
3
+ CHAINCODE_ERROR_MESSAGE_PREFIX = 'transaction returned with failure:'.freeze
4
+
5
+ def self.create(message)
6
+ if message.start_with? CHAINCODE_ERROR_MESSAGE_PREFIX
7
+ ChaincodeError.new message.gsub(CHAINCODE_ERROR_MESSAGE_PREFIX, '')
8
+ else
9
+ UnknownError.new message
10
+ end
11
+ end
12
+ end
13
+
14
+ class Error < StandardError
15
+ attr_reader :code, :errors
16
+
17
+ def initialize(message, code = 0, errors = {})
18
+ super message
19
+
20
+ @code = code
21
+ @errors = errors
22
+ end
23
+
24
+ def response
25
+ Hashie::Mash.new success: false,
26
+ code: code,
27
+ result: {},
28
+ message: message,
29
+ errors: errors
30
+ end
31
+ end
32
+
33
+ class ChaincodeError < Fabric::Error
34
+ def initialize(message)
35
+ response = Hashie::Mash.new JSON.parse(message)
36
+
37
+ super response.message, response.code, response.errors
38
+ end
39
+ end
40
+
41
+ class OrdererError < Fabric::Error; end
42
+
43
+ class TransactionError < Fabric::Error
44
+ def initialize(status)
45
+ super "Transaction failed (#{status})", "TX_STATUS_#{status}"
46
+ end
47
+ end
48
+
49
+ class NetworkOfflineError < Fabric::Error; end
50
+
51
+ class UnknownError < Fabric::Error; end
52
+ end
@@ -0,0 +1,81 @@
1
+ module Fabric
2
+ class EventHub
3
+ attr_reader :url, :identity, :logger, :crypto_suite, :channel_id
4
+ attr_reader :channel, :connection, :queue
5
+
6
+ MAX_BLOCK_NUMBER = 1_000_000_000
7
+
8
+ def initialize(opts = {})
9
+ @url = opts[:url]
10
+ @identity = opts[:identity]
11
+ @crypto_suite = opts[:crypto_suite]
12
+ @logger = opts[:logger]
13
+ @channel_id = opts[:channel_id]
14
+
15
+ @channel = ::Protos::Deliver::Stub.new url, :this_channel_is_insecure
16
+ @queue = Fabric::EnumeratorQueue.new channel
17
+ @connection = channel.deliver(queue.each).each
18
+ end
19
+
20
+ def observe(start_block = :newest, stop_block = MAX_BLOCK_NUMBER)
21
+ tx_info = Fabric::TransactionInfo.new crypto_suite, identity
22
+ seek_header = build_seek_header tx_info
23
+ seek_info = build_seek_info start_block, stop_block
24
+ envelope = build_envelope tx_info, seek_header, seek_info
25
+
26
+ loop do
27
+ queue.push envelope
28
+
29
+ event = connection.next
30
+
31
+ block = Fabric::BlockDecoder.decode_block(event.block)
32
+
33
+ yield block if block_given?
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def build_envelope(tx_info, seek_header, seek_info)
40
+ seek_payload = ::Common::Payload.new(
41
+ header: seek_header,
42
+ data: seek_info.to_proto
43
+ )
44
+
45
+ ::Common::Envelope.new signature: tx_info.identity.sign(seek_payload.to_proto),
46
+ payload: seek_payload.to_proto
47
+ end
48
+
49
+ def build_seek_header(tx_info)
50
+ seek_info_header = Fabric::Helper.build_channel_header(
51
+ type: ::Common::HeaderType::DELIVER_SEEK_INFO,
52
+ channel_id: channel_id,
53
+ tx_id: tx_info.tx_id
54
+ )
55
+
56
+ ::Common::Header.new(
57
+ channel_header: seek_info_header.to_proto,
58
+ signature_header: tx_info.signature_header.to_proto
59
+ )
60
+ end
61
+
62
+ def build_seek_info(start_block, stop_block)
63
+ ::Orderer::SeekInfo.new(
64
+ start: build_seek_position(start_block),
65
+ stop: build_seek_position(stop_block),
66
+ behavior: ::Orderer::SeekInfo::SeekBehavior::BLOCK_UNTIL_READY
67
+ )
68
+ end
69
+
70
+ def build_seek_position(block_number)
71
+ case block_number
72
+ when :newest then ::Orderer::SeekPosition.new(newest: ::Orderer::SeekNewest.new)
73
+ when :oldest then ::Orderer::SeekPosition.new(oldest: ::Orderer::SeekOldest.new)
74
+ else
75
+ ::Orderer::SeekPosition.new(
76
+ specified: ::Orderer::SeekSpecified.new(number: block_number)
77
+ )
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,31 @@
1
+ module Fabric
2
+ module Helper
3
+ def self.build_channel_header(opts)
4
+ header = Common::ChannelHeader.new type: opts[:type],
5
+ channel_id: opts[:channel_id],
6
+ tx_id: opts[:tx_id],
7
+ timestamp: opts[:timestamp] || build_timestamp,
8
+ version: 1
9
+
10
+ header.extension = build_channel_header_extension(opts) if opts[:chaincode_id]
11
+
12
+ header
13
+ end
14
+
15
+ def self.build_channel_header_extension(opts)
16
+ id = Protos::ChaincodeID.new name: opts[:chaincode_id]
17
+
18
+ Protos::ChaincodeHeaderExtension.new chaincode_id: id
19
+ end
20
+
21
+ def self.build_timestamp
22
+ now = Time.current
23
+
24
+ Google::Protobuf::Timestamp.new seconds: now.to_i, nanos: now.nsec
25
+ end
26
+
27
+ def self.timestamp_to_time(timestamp)
28
+ (timestamp.seconds * 1000 + timestamp.nanos / 10**6).to_i
29
+ end
30
+ end
31
+ end
@@ -2,35 +2,41 @@ require 'msp/identities_pb'
2
2
 
3
3
  module Fabric
4
4
  class Identity
5
- attr_reader :certificate, :public_key, :private_key, :msp_id, :crypto_suite,
6
- :key, :iv
7
-
8
- def initialize(args)
9
- @certificate = args[:certificate]
10
- @public_key = args[:public_key]
11
- @private_key = args[:private_key]
12
- @msp_id = args[:msp_id]
13
- @crypto_suite = args[:crypto_suite]
14
- @key = args[:key].to_s
15
- @iv = args[:iv].to_s
5
+ attr_reader :private_key,
6
+ :public_key,
7
+ :address
8
+
9
+ attr_accessor :certificate, :mspid
10
+
11
+ def initialize(crypto_suite, opts = {})
12
+ @crypto_suite = crypto_suite
13
+
14
+ @private_key = opts[:private_key] || @crypto_suite.generate_private_key
15
+ @public_key = opts[:public_key] || @crypto_suite.restore_public_key(private_key)
16
+ @certificate = opts[:certificate]
17
+ @mspid = opts[:mspid]
18
+
19
+ @address = @crypto_suite.address_from_public_key public_key
16
20
  end
17
21
 
18
- def serialize
19
- Msp::SerializedIdentity.new(mspid: msp_id, id_bytes: certificate).to_proto
22
+ def generate_csr(attrs = [])
23
+ @crypto_suite.generate_csr private_key, attrs
20
24
  end
21
25
 
22
26
  def sign(message)
23
- digest = crypto_suite.digest message
27
+ @crypto_suite.sign(private_key, message)
28
+ end
24
29
 
25
- crypto_suite.sign private_key, digest
30
+ def shared_secret_by(public_key)
31
+ @crypto_suite.build_shared_key private_key, public_key
26
32
  end
27
33
 
28
- def encrypt(message)
29
- crypto_suite.encrypt key, iv, message
34
+ def decoded_certificate
35
+ Base64.strict_decode64 certificate
30
36
  end
31
37
 
32
- def decrypt(message)
33
- crypto_suite.decrypt key, iv, message
38
+ def serialize
39
+ Msp::SerializedIdentity.new(mspid: mspid, id_bytes: decoded_certificate).to_proto
34
40
  end
35
41
  end
36
42
  end
@@ -0,0 +1,37 @@
1
+ module Fabric
2
+ class Logger
3
+ LOGGER_TAG = 'HYPERLEDGER FABRIC'.colorize(:green).freeze
4
+ FILTERED_MASK = '[FILTERED]'.freeze
5
+
6
+ attr_reader :logger, :filters
7
+
8
+ def initialize(logger, filters = [])
9
+ @logger = logger
10
+ @filters = [filters]
11
+ end
12
+
13
+ def error(*args)
14
+ return unless logger
15
+
16
+ logger.tagged(LOGGER_TAG) { |logger| logger.error filter_message(args.join('|')) }
17
+ end
18
+
19
+ def info(*args)
20
+ return unless logger
21
+
22
+ logger.tagged(LOGGER_TAG) { |logger| logger.info filter_message(args.join('|')) }
23
+ end
24
+
25
+ def debug(*args)
26
+ return unless logger
27
+
28
+ logger.tagged(LOGGER_TAG) { |logger| logger.debug filter_message(args.join('|')) }
29
+ end
30
+
31
+ private
32
+
33
+ def filter_message(message)
34
+ filters.inject(message) { |msg, filter| msg.gsub(filter, FILTERED_MASK) }
35
+ end
36
+ end
37
+ end
@@ -2,18 +2,34 @@ require 'orderer/ab_services_pb.rb'
2
2
 
3
3
  module Fabric
4
4
  class Orderer
5
- attr_reader :url, :opts, :client
5
+ attr_reader :url, :opts, :client, :logger
6
6
 
7
7
  def initialize(args)
8
8
  @url = args[:url]
9
9
  @opts = args[:opts]
10
+ @logger = args[:logger]
11
+
10
12
  @client = ::Orderer::AtomicBroadcast::Stub.new url, :this_channel_is_insecure
11
13
  end
12
14
 
13
15
  def send_broadcast(envelope)
14
- client.broadcast([envelope]) do |response|
16
+ logging :send_broadcast_request, envelope.to_h
17
+
18
+ client.broadcast([envelope]).each do |response|
19
+ logging :send_broadcast_response, response.to_h
20
+
21
+ raise OrdererError response.message unless response.status == :SUCCESS
22
+
15
23
  yield response if block_given?
16
24
  end
17
25
  end
26
+
27
+ private
28
+
29
+ def logging(section, message)
30
+ logger.debug section.to_s.upcase.colorize(:yellow),
31
+ url.colorize(:red),
32
+ message.to_s.colorize(:blue)
33
+ end
18
34
  end
19
35
  end
data/lib/fabric/peer.rb CHANGED
@@ -1,58 +1,37 @@
1
- require 'peer/query_pb'
1
+ require 'peer/peer_services_pb'
2
2
 
3
3
  module Fabric
4
4
  class Peer
5
- attr_reader :url, :opts, :identity_context, :client
5
+ attr_reader :url, :opts, :client, :logger
6
6
 
7
7
  def initialize(args)
8
8
  @url = args[:url]
9
9
  @opts = args[:opts]
10
- @identity_context = args[:identity_context]
10
+ @logger = args[:logger]
11
+
11
12
  @client = Protos::Endorser::Stub.new url, :this_channel_is_insecure
12
13
  end
13
14
 
14
15
  def send_process_proposal(proposal)
15
- client.process_proposal proposal
16
- end
16
+ logging :send_process_proposal_request, proposal.to_h
17
17
 
18
- def query_channels
19
- request = {
20
- targets: [self],
21
- chaincode_id: Constants::CSCC,
22
- transaction: TransactionID.new(identity_context),
23
- function: Constants::FUNC_GET_CHANNELS,
24
- args: []
25
- }
18
+ response = client.process_proposal proposal
26
19
 
27
- responses = PeerEndorser.send_transaction_proposal request, '', identity_context
28
- response = responses.first
20
+ logging :send_process_proposal_response, response.to_h
29
21
 
30
- Protos::ChannelQueryResponse.decode response.response.payload
22
+ response
31
23
  end
32
24
 
33
- def query_config_block(channel_id)
34
- request = {
35
- targets: [self],
36
- chaincode_id: Constants::CSCC,
37
- transaction: TransactionID.new(identity_context),
38
- function: Constants::FUNC_GET_CONFIG_BLOCK,
39
- args: [channel_id]
40
- }
41
-
42
- responses = PeerEndorser.send_transaction_proposal request, '', identity_context
43
- proposal_response = responses.first
44
-
45
- extract_config_enveloper proposal_response
25
+ def create_event_hub
26
+ EventHub.new url: url, opts: opts, logger: logger
46
27
  end
47
28
 
48
29
  private
49
30
 
50
- def extract_config_enveloper(proposal_response)
51
- block = Common::Block.decode proposal_response.response.payload
52
- envelope = Common::Envelope.decode block.data.data.first
53
- payload = Common::Payload.decode envelope.payload
54
-
55
- Common::ConfigEnvelope.decode payload.data
56
- end
31
+ def logging(section, message)
32
+ logger.debug section.to_s.upcase.colorize(:yellow),
33
+ url.colorize(:red),
34
+ message.to_s.colorize(:blue)
35
+ end
57
36
  end
58
37
  end
@@ -0,0 +1,100 @@
1
+ module Fabric
2
+ class Proposal
3
+ attr_reader :crypto_suite, :identity, :request
4
+
5
+ def initialize(crypto_suite, identity, request = {})
6
+ @crypto_suite = crypto_suite
7
+ @identity = identity
8
+ @request = request
9
+
10
+ assign_tx request[:transaction_info] if request[:transaction_info]
11
+ end
12
+
13
+ def nonce
14
+ @nonce ||= crypto_suite.generate_nonce
15
+ end
16
+
17
+ def channel_id
18
+ request[:channel_id]
19
+ end
20
+
21
+ def chaincode_id
22
+ request[:chaincode_id]
23
+ end
24
+
25
+ def args
26
+ request[:args].compact.map &:to_s
27
+ end
28
+
29
+ def transient
30
+ request[:transient] || {}
31
+ end
32
+
33
+ def transaction_id
34
+ request[:transaction_id]
35
+ end
36
+
37
+ def tx_id
38
+ @tx_id ||= crypto_suite.hexdigest(nonce + identity.serialize)
39
+ end
40
+
41
+ def proposal
42
+ @proposal ||= Protos::Proposal.new header: header.to_proto,
43
+ payload: chaincode_proposal.to_proto
44
+ end
45
+
46
+ def signed_proposal
47
+ proposal_bytes = proposal.to_proto
48
+ signature = identity.sign proposal_bytes
49
+
50
+ Protos::SignedProposal.new proposal_bytes: proposal_bytes, signature: signature
51
+ end
52
+
53
+ def header
54
+ Common::Header.new channel_header: channel_header.to_proto,
55
+ signature_header: signature_header.to_proto
56
+ end
57
+
58
+ def channel_header
59
+ Common::ChannelHeader.new type: Common::HeaderType::ENDORSER_TRANSACTION,
60
+ channel_id: channel_id, tx_id: tx_id,
61
+ extension: channel_header_extension.to_proto,
62
+ timestamp: tx_timestamp,
63
+ version: Constants::CHANNEL_HEADER_VERSION
64
+ end
65
+
66
+ def channel_header_extension
67
+ id = Protos::ChaincodeID.new name: chaincode_id
68
+
69
+ Protos::ChaincodeHeaderExtension.new chaincode_id: id
70
+ end
71
+
72
+ def tx_timestamp
73
+ now = Time.current
74
+
75
+ @tx_timestamp ||= Google::Protobuf::Timestamp.new seconds: now.to_i, nanos: now.nsec
76
+ end
77
+
78
+ def signature_header
79
+ Common::SignatureHeader.new creator: identity.serialize, nonce: nonce
80
+ end
81
+
82
+ def chaincode_proposal
83
+ id = Protos::ChaincodeID.new name: chaincode_id
84
+ chaincode_input = Protos::ChaincodeInput.new args: args
85
+ chaincode_spec = Protos::ChaincodeSpec.new type: Protos::ChaincodeSpec::Type::NODE,
86
+ chaincode_id: id,
87
+ input: chaincode_input
88
+ input = Protos::ChaincodeInvocationSpec.new chaincode_spec: chaincode_spec
89
+
90
+ Protos::ChaincodeProposalPayload.new input: input.to_proto, TransientMap: transient
91
+ end
92
+
93
+ private
94
+
95
+ def assign_tx(transaction_info)
96
+ @tx_id = transaction_info[:tx_id]
97
+ @nonce = crypto_suite.decode_hex transaction_info[:nonce_hex]
98
+ end
99
+ end
100
+ end