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.
- checksums.yaml +4 -4
- data/lib/fabric/block_decoder.rb +299 -0
- data/lib/fabric/chaincode_response.rb +47 -0
- data/lib/fabric/channel.rb +55 -34
- data/lib/fabric/client.rb +107 -25
- data/lib/fabric/configuration.rb +12 -4
- data/lib/fabric/constants.rb +1 -1
- data/lib/fabric/crypto_suite.rb +145 -0
- data/lib/fabric/enumerator_queue.rb +26 -0
- data/lib/fabric/error.rb +52 -0
- data/lib/fabric/event_hub.rb +81 -0
- data/lib/fabric/helper.rb +31 -0
- data/lib/fabric/identity.rb +25 -19
- data/lib/fabric/logger.rb +37 -0
- data/lib/fabric/orderer.rb +18 -2
- data/lib/fabric/peer.rb +15 -36
- data/lib/fabric/proposal.rb +100 -0
- data/lib/{protos → fabric/protos}/common/collection_pb.rb +14 -14
- data/lib/{protos → fabric/protos}/common/common_pb.rb +37 -36
- data/lib/fabric/protos/common/configtx_pb.rb +71 -0
- data/lib/{protos → fabric/protos}/common/configuration_pb.rb +13 -13
- data/lib/{protos → fabric/protos}/common/ledger_pb.rb +2 -2
- data/lib/{protos → fabric/protos}/common/policies_pb.rb +19 -19
- data/lib/fabric/protos/discovery/protocol_pb.rb +120 -0
- data/lib/{protos → fabric/protos}/discovery/protocol_services_pb.rb +0 -1
- data/lib/fabric/protos/gossip/message_pb.rb +233 -0
- data/lib/{protos → fabric/protos}/gossip/message_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/idemix/idemix_pb.rb +37 -37
- data/lib/{protos → fabric/protos}/ledger/queryresult/kv_query_result_pb.rb +5 -5
- data/lib/fabric/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +85 -0
- data/lib/fabric/protos/ledger/rwset/rwset_pb.rb +46 -0
- data/lib/{protos → fabric/protos}/msp/identities_pb.rb +4 -4
- data/lib/{protos → fabric/protos}/msp/msp_config_pb.rb +27 -27
- data/lib/{protos → fabric/protos}/msp/msp_principal_pb.rb +20 -20
- data/lib/fabric/protos/orderer/ab_pb.rb +52 -0
- data/lib/{protos → fabric/protos}/orderer/ab_services_pb.rb +0 -1
- data/lib/fabric/protos/orderer/cluster_pb.rb +31 -0
- data/lib/fabric/protos/orderer/cluster_services_pb.rb +31 -0
- data/lib/{protos → fabric/protos}/orderer/configuration_pb.rb +11 -10
- data/lib/fabric/protos/orderer/etcdraft/configuration_pb.rb +21 -0
- data/lib/{protos → fabric/protos}/orderer/kafka_pb.rb +16 -16
- data/lib/{protos → fabric/protos}/peer/admin_pb.rb +12 -12
- data/lib/{protos → fabric/protos}/peer/admin_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/peer/chaincode_event_pb.rb +2 -2
- data/lib/fabric/protos/peer/chaincode_pb.rb +60 -0
- data/lib/fabric/protos/peer/chaincode_shim_pb.rb +129 -0
- data/lib/{protos → fabric/protos}/peer/chaincode_shim_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/peer/configuration_pb.rb +10 -10
- data/lib/fabric/protos/peer/events_pb.rb +45 -0
- data/lib/fabric/protos/peer/events_services_pb.rb +34 -0
- data/lib/{protos → fabric/protos}/peer/peer_pb.rb +5 -5
- data/lib/{protos → fabric/protos}/peer/peer_services_pb.rb +0 -1
- data/lib/{protos → fabric/protos}/peer/proposal_pb.rb +13 -13
- data/lib/{protos → fabric/protos}/peer/proposal_response_pb.rb +11 -11
- data/lib/{protos → fabric/protos}/peer/query_pb.rb +10 -10
- data/lib/{protos → fabric/protos}/peer/resources_pb.rb +12 -12
- data/lib/{protos → fabric/protos}/peer/signed_cc_dep_spec_pb.rb +3 -3
- data/lib/{protos → fabric/protos}/peer/transaction_pb.rb +22 -18
- data/lib/fabric/protos/token/prover_pb.rb +66 -0
- data/lib/fabric/protos/token/prover_services_pb.rb +33 -0
- data/lib/fabric/protos/token/transaction_pb.rb +41 -0
- data/lib/{protos → fabric/protos}/transientstore/transientstore_pb.rb +4 -4
- data/lib/fabric/queue.rb +26 -0
- data/lib/fabric/transaction.rb +51 -0
- data/lib/fabric/transaction_info.rb +20 -0
- data/lib/fabric/version.rb +1 -1
- data/lib/fabric.rb +74 -0
- data/lib/fabric_ca/attribute.rb +7 -0
- data/lib/fabric_ca/client.rb +11 -19
- data/lib/fabric_ca/configuration.rb +4 -2
- data/lib/fabric_ca/connection.rb +22 -20
- data/lib/fabric_ca/error.rb +3 -2
- data/lib/fabric_ca/faraday_middleware/basic_auth.rb +3 -3
- data/lib/fabric_ca/faraday_middleware/raise_http_exception.rb +13 -13
- data/lib/fabric_ca/faraday_middleware/token_auth.rb +10 -12
- data/lib/fabric_ca/request.rb +13 -24
- data/lib/fabric_ca/version.rb +1 -1
- data/lib/fabric_ca.rb +16 -0
- data/lib/hyperledger-fabric-sdk.rb +2 -47
- metadata +161 -61
- data/lib/crypto_suite/ecdsa_aes.rb +0 -86
- data/lib/fabric/peer_endorser.rb +0 -85
- data/lib/fabric/transaction_id.rb +0 -11
- data/lib/fabric/user.rb +0 -24
- data/lib/fabric_ca/tools.rb +0 -35
- data/lib/protos/common/configtx_pb.rb +0 -71
- data/lib/protos/discovery/protocol_pb.rb +0 -119
- data/lib/protos/gossip/message_pb.rb +0 -233
- data/lib/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +0 -85
- data/lib/protos/ledger/rwset/rwset_pb.rb +0 -46
- data/lib/protos/orderer/ab_pb.rb +0 -52
- data/lib/protos/peer/chaincode_pb.rb +0 -60
- data/lib/protos/peer/chaincode_shim_pb.rb +0 -94
- data/lib/protos/peer/events_pb.rb +0 -98
- 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
|
data/lib/fabric/error.rb
ADDED
@@ -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
|
data/lib/fabric/identity.rb
CHANGED
@@ -2,35 +2,41 @@ require 'msp/identities_pb'
|
|
2
2
|
|
3
3
|
module Fabric
|
4
4
|
class Identity
|
5
|
-
attr_reader :
|
6
|
-
:
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
|
14
|
-
@
|
15
|
-
@
|
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
|
19
|
-
|
22
|
+
def generate_csr(attrs = [])
|
23
|
+
@crypto_suite.generate_csr private_key, attrs
|
20
24
|
end
|
21
25
|
|
22
26
|
def sign(message)
|
23
|
-
|
27
|
+
@crypto_suite.sign(private_key, message)
|
28
|
+
end
|
24
29
|
|
25
|
-
|
30
|
+
def shared_secret_by(public_key)
|
31
|
+
@crypto_suite.build_shared_key private_key, public_key
|
26
32
|
end
|
27
33
|
|
28
|
-
def
|
29
|
-
|
34
|
+
def decoded_certificate
|
35
|
+
Base64.strict_decode64 certificate
|
30
36
|
end
|
31
37
|
|
32
|
-
def
|
33
|
-
|
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
|
data/lib/fabric/orderer.rb
CHANGED
@@ -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
|
-
|
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/
|
1
|
+
require 'peer/peer_services_pb'
|
2
2
|
|
3
3
|
module Fabric
|
4
4
|
class Peer
|
5
|
-
attr_reader :url, :opts, :
|
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
|
-
@
|
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
|
-
|
16
|
-
end
|
16
|
+
logging :send_process_proposal_request, proposal.to_h
|
17
17
|
|
18
|
-
|
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
|
-
|
28
|
-
response = responses.first
|
20
|
+
logging :send_process_proposal_response, response.to_h
|
29
21
|
|
30
|
-
|
22
|
+
response
|
31
23
|
end
|
32
24
|
|
33
|
-
def
|
34
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|