hyperledger-fabric-sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|