hyperledger-fabric-sdk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/lib/crypto_suite/ecdsa_aes.rb +86 -0
  3. data/lib/fabric/channel.rb +54 -0
  4. data/lib/fabric/client.rb +45 -0
  5. data/lib/fabric/configuration.rb +25 -0
  6. data/lib/fabric/constants.rb +18 -0
  7. data/lib/fabric/identity.rb +36 -0
  8. data/lib/fabric/orderer.rb +19 -0
  9. data/lib/fabric/peer.rb +58 -0
  10. data/lib/fabric/peer_endorser.rb +85 -0
  11. data/lib/fabric/transaction_id.rb +11 -0
  12. data/lib/fabric/user.rb +24 -0
  13. data/lib/fabric/version.rb +3 -0
  14. data/lib/fabric_ca/client.rb +51 -0
  15. data/lib/fabric_ca/configuration.rb +25 -0
  16. data/lib/fabric_ca/connection.rb +32 -0
  17. data/lib/fabric_ca/error.rb +11 -0
  18. data/lib/fabric_ca/faraday_middleware/basic_auth.rb +33 -0
  19. data/lib/fabric_ca/faraday_middleware/raise_http_exception.rb +47 -0
  20. data/lib/fabric_ca/faraday_middleware/token_auth.rb +38 -0
  21. data/lib/fabric_ca/request.rb +50 -0
  22. data/lib/fabric_ca/response.rb +10 -0
  23. data/lib/fabric_ca/tools.rb +35 -0
  24. data/lib/fabric_ca/version.rb +3 -0
  25. data/lib/hyperledger-fabric-sdk.rb +47 -0
  26. data/lib/protos/common/collection_pb.rb +42 -0
  27. data/lib/protos/common/common_pb.rb +106 -0
  28. data/lib/protos/common/configtx_pb.rb +71 -0
  29. data/lib/protos/common/configuration_pb.rb +33 -0
  30. data/lib/protos/common/ledger_pb.rb +16 -0
  31. data/lib/protos/common/policies_pb.rb +52 -0
  32. data/lib/protos/discovery/protocol_pb.rb +119 -0
  33. data/lib/protos/discovery/protocol_services_pb.rb +30 -0
  34. data/lib/protos/gossip/message_pb.rb +233 -0
  35. data/lib/protos/gossip/message_services_pb.rb +31 -0
  36. data/lib/protos/idemix/idemix_pb.rb +93 -0
  37. data/lib/protos/ledger/queryresult/kv_query_result_pb.rb +24 -0
  38. data/lib/protos/ledger/rwset/kvrwset/kv_rwset_pb.rb +85 -0
  39. data/lib/protos/ledger/rwset/rwset_pb.rb +46 -0
  40. data/lib/protos/msp/identities_pb.rb +23 -0
  41. data/lib/protos/msp/msp_config_pb.rb +72 -0
  42. data/lib/protos/msp/msp_principal_pb.rb +54 -0
  43. data/lib/protos/orderer/ab_pb.rb +52 -0
  44. data/lib/protos/orderer/ab_services_pb.rb +41 -0
  45. data/lib/protos/orderer/configuration_pb.rb +32 -0
  46. data/lib/protos/orderer/kafka_pb.rb +45 -0
  47. data/lib/protos/peer/admin_pb.rb +41 -0
  48. data/lib/protos/peer/admin_services_pb.rb +33 -0
  49. data/lib/protos/peer/chaincode_event_pb.rb +17 -0
  50. data/lib/protos/peer/chaincode_pb.rb +60 -0
  51. data/lib/protos/peer/chaincode_shim_pb.rb +94 -0
  52. data/lib/protos/peer/chaincode_shim_services_pb.rb +30 -0
  53. data/lib/protos/peer/configuration_pb.rb +27 -0
  54. data/lib/protos/peer/events_pb.rb +98 -0
  55. data/lib/protos/peer/events_services_pb.rb +59 -0
  56. data/lib/protos/peer/peer_pb.rb +21 -0
  57. data/lib/protos/peer/peer_services_pb.rb +37 -0
  58. data/lib/protos/peer/proposal_pb.rb +40 -0
  59. data/lib/protos/peer/proposal_response_pb.rb +35 -0
  60. data/lib/protos/peer/query_pb.rb +32 -0
  61. data/lib/protos/peer/resources_pb.rb +34 -0
  62. data/lib/protos/peer/signed_cc_dep_spec_pb.rb +17 -0
  63. data/lib/protos/peer/transaction_pb.rb +72 -0
  64. data/lib/protos/transientstore/transientstore_pb.rb +18 -0
  65. metadata +123 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8868d76ed70adc4cedf983ad30718b1964bdd4a4a06291bc336d7381bc152a74
4
+ data.tar.gz: 97809db15dee6a3f8ac534a63eb3933895e8f0fa0ebd255b10569124e5ff06c4
5
+ SHA512:
6
+ metadata.gz: e4c1c49bdc093de69d552136954eacf30f0e92128222f5e878d760e71dd94ac08720ad832e8172014fb2363ce507963fe1099f1c7589878875c412704063de8f
7
+ data.tar.gz: e91abaeeee3053694b18362ab2fff01132267782ae6fdc0e01ed8bcc04540ff565fa70ae6bd5e4931068664f8ae51230008792e3a9cf1592c23ba5284bead9e0
@@ -0,0 +1,86 @@
1
+ require 'openssl'
2
+
3
+ module CryptoSuite
4
+ class ECDSA_AES
5
+ DEFAULT_KEY_SIZE = 256.freeze
6
+ DEFAULT_NONCE_LENGTH = 24.freeze
7
+ DEFAULT_DIGEST_ALGORITHM = 'SHA256'.freeze
8
+ DEFAULT_AES_KEY_SIZE = 128.freeze
9
+
10
+ EC_CURVES = { 256 => 'prime256v1', 384 => 'secp384r1' }.freeze
11
+
12
+ attr_reader :key_size, :nonce_length, :digest_algorithm, :digest, :cipher
13
+
14
+ def initialize(opts = {})
15
+ @key_size = opts[:key_size] || DEFAULT_KEY_SIZE
16
+ @nonce_length = opts[:nonce_length] || DEFAULT_NONCE_LENGTH
17
+ @digest_algorithm = opts[:digest_algorithm] || DEFAULT_DIGEST_ALGORITHM
18
+ @digest = OpenSSL::Digest.new(digest_algorithm)
19
+ @cipher = OpenSSL::Cipher::AES.new(opts[:aes_key_size] || DEFAULT_AES_KEY_SIZE, :CBC)
20
+ end
21
+
22
+ def generate_nonce
23
+ OpenSSL::Random.random_bytes nonce_length
24
+ end
25
+
26
+ def hexdigest(message)
27
+ @digest.hexdigest message
28
+ end
29
+
30
+ def digest(message)
31
+ @digest.digest message
32
+ end
33
+
34
+ def sign(private_key, msg)
35
+ key = OpenSSL::PKey::EC.new private_key
36
+ signature = key.dsa_sign_asn1 msg
37
+ sequence = OpenSSL::ASN1.decode signature
38
+ sequence = prevent_malleability sequence, key.group.order
39
+
40
+ sequence.to_der
41
+ end
42
+
43
+ def generate_private_key
44
+ key = OpenSSL::PKey::EC.new EC_CURVES[key_size]
45
+ key.generate_key!
46
+
47
+ key.to_pem
48
+ end
49
+
50
+ def generate_csr(private_key, options = [])
51
+ key = OpenSSL::PKey::EC.new private_key
52
+ req = OpenSSL::X509::Request.new
53
+ req.public_key = key
54
+ req.subject = OpenSSL::X509::Name.new(options)
55
+ req.sign key, @digest
56
+
57
+ req
58
+ end
59
+
60
+ def encrypt(key, iv, message)
61
+ cipher.encrypt key, iv
62
+
63
+ Base64.strict_encode64(cipher.update(message) + cipher.final)
64
+ end
65
+
66
+ def decrypt(key, iv, message)
67
+ cipher.decrypt key, iv
68
+
69
+ cipher.update(Base64.strict_decode64(message)) + cipher.final
70
+ rescue OpenSSL::Cipher::CipherError
71
+ nil
72
+ end
73
+
74
+ private
75
+
76
+ def prevent_malleability(sequence, order)
77
+ half_order = order >> 1
78
+
79
+ if (half_key = sequence.value[1].value) > half_order
80
+ sequence.value[1].value = order - half_key
81
+ end
82
+
83
+ sequence
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,54 @@
1
+ require 'peer/transaction_pb'
2
+
3
+ module Fabric
4
+ class Channel
5
+ attr_reader :identity_context, :name, :peers, :orderers
6
+
7
+ def initialize(args)
8
+ @identity_context = args[:identity_context]
9
+ @name = args[:name]
10
+ @peers = args[:peers] || []
11
+ @orderers = args[:orderers] || []
12
+ end
13
+
14
+ def query_by_chaincode(request)
15
+ request[:targets] ||= peers
16
+ request[:transaction] = TransactionID.new identity_context
17
+
18
+ PeerEndorser.send_transaction_proposal request, name, identity_context
19
+ end
20
+
21
+ def send_transaction(request, &block)
22
+ header = Common::Header.decode request[:proposal].header
23
+ chaincode_action_payload = build_chaincode_action request
24
+
25
+ transaction_action = Protos::TransactionAction.new header: header.signature_header,
26
+ payload: chaincode_action_payload.to_proto
27
+ transaction = Protos::Transaction.new actions: [transaction_action]
28
+
29
+ payload = Common::Payload.new header: header,
30
+ data: transaction.to_proto
31
+
32
+ envelope = Common::Envelope.new signature: identity_context.identity.sign(payload.to_proto),
33
+ payload: payload.to_proto
34
+
35
+ orderers.first.send_broadcast envelope, &block
36
+ end
37
+
38
+ private
39
+
40
+ def build_chaincode_action(request)
41
+ responses = request[:responses].select { |response| response.response.status == 200 }
42
+ endorsements = responses.map { |response| response.endorsement }
43
+ chaincode_endorser_action =
44
+ Protos::ChaincodeEndorsedAction.new proposal_response_payload: responses.first.payload,
45
+ endorsements: endorsements
46
+
47
+ payload = Protos::ChaincodeProposalPayload.decode request[:proposal].payload
48
+ payload_no_trans = Protos::ChaincodeProposalPayload.new input: payload.input
49
+
50
+ Protos::ChaincodeActionPayload.new action: chaincode_endorser_action,
51
+ chaincode_proposal_payload: payload_no_trans.to_proto
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ module Fabric
2
+ class Client
3
+ attr_reader :identity_context, :orderers, :peers, :channels
4
+
5
+ def initialize(options = {})
6
+ options = Fabric.options.merge(options)
7
+
8
+ @identity_context = options[:identity_context]
9
+ @orderers = {}
10
+ @channels = {}
11
+ @peers = {}
12
+ end
13
+
14
+ def config
15
+ conf = {}
16
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
17
+ conf[key] = public_send key
18
+ end
19
+
20
+ conf
21
+ end
22
+
23
+ def new_channel(name)
24
+ channels[name] ||= Channel.new name: name,
25
+ orderers: orderers.values , peers: peers.values,
26
+ identity_context: identity_context
27
+
28
+ channels[name]
29
+ end
30
+
31
+ def new_peer(url, opts = {})
32
+ peers[url] ||= Peer.new url: url, opts: opts,
33
+ identity_context: identity_context
34
+
35
+ peers[url]
36
+ end
37
+
38
+ def new_orderer(url, opts = {})
39
+ orderers[url] ||= Orderer.new url: url, opts: opts,
40
+ identity_context: identity_context
41
+
42
+ orderers[url]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ module Fabric
2
+ module Configuration
3
+ VALID_OPTIONS_KEYS = [:identity_context, :orderers, :peers]
4
+
5
+ attr_accessor *VALID_OPTIONS_KEYS
6
+
7
+ def self.extended(base)
8
+ base.reset
9
+ end
10
+
11
+ def configure
12
+ yield self
13
+ end
14
+
15
+ def options
16
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
17
+ option.merge!(key => send(key))
18
+ end
19
+ end
20
+
21
+ def reset
22
+ VALID_OPTIONS_KEYS.each {|key| send("#{key}=", nil)}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module Fabric
2
+ module Constants
3
+ ## System Chaincodes
4
+ LSCC = 'lscc'.freeze
5
+ QSCC = 'qscc'.freeze
6
+ CSCC = 'cscc'.freeze
7
+
8
+ ## System Channels
9
+ SYSTEM_CHANNEL_NAME = 'testchainid'.freeze
10
+
11
+ ## System Functions
12
+ FUNC_GET_CHANNELS = 'GetChannels'.freeze
13
+ FUNC_GET_CONFIG_BLOCK = 'GetConfigBlock'.freeze
14
+
15
+ ## Variables
16
+ CHANNEL_HEADER_VERSION = 1.freeze
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ require 'msp/identities_pb'
2
+
3
+ module Fabric
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
16
+ end
17
+
18
+ def serialize
19
+ Msp::SerializedIdentity.new(mspid: msp_id, id_bytes: certificate).to_proto
20
+ end
21
+
22
+ def sign(message)
23
+ digest = crypto_suite.digest message
24
+
25
+ crypto_suite.sign private_key, digest
26
+ end
27
+
28
+ def encrypt(message)
29
+ crypto_suite.encrypt key, iv, message
30
+ end
31
+
32
+ def decrypt(message)
33
+ crypto_suite.decrypt key, iv, message
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ require 'orderer/ab_services_pb.rb'
2
+
3
+ module Fabric
4
+ class Orderer
5
+ attr_reader :url, :opts, :client
6
+
7
+ def initialize(args)
8
+ @url = args[:url]
9
+ @opts = args[:opts]
10
+ @client = ::Orderer::AtomicBroadcast::Stub.new url, :this_channel_is_insecure
11
+ end
12
+
13
+ def send_broadcast(envelope)
14
+ client.broadcast([envelope]) do |response|
15
+ yield response if block_given?
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,58 @@
1
+ require 'peer/query_pb'
2
+
3
+ module Fabric
4
+ class Peer
5
+ attr_reader :url, :opts, :identity_context, :client
6
+
7
+ def initialize(args)
8
+ @url = args[:url]
9
+ @opts = args[:opts]
10
+ @identity_context = args[:identity_context]
11
+ @client = Protos::Endorser::Stub.new url, :this_channel_is_insecure
12
+ end
13
+
14
+ def send_process_proposal(proposal)
15
+ client.process_proposal proposal
16
+ end
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
+ }
26
+
27
+ responses = PeerEndorser.send_transaction_proposal request, '', identity_context
28
+ response = responses.first
29
+
30
+ Protos::ChannelQueryResponse.decode response.response.payload
31
+ end
32
+
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
46
+ end
47
+
48
+ private
49
+
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
57
+ end
58
+ end
@@ -0,0 +1,85 @@
1
+ require 'peer/peer_services_pb'
2
+
3
+ module Fabric
4
+ class PeerEndorser
5
+ def self.send_transaction_proposal(request, channel_id, identity_context)
6
+ args = request[:args].unshift request[:function]
7
+
8
+ transaction = request[:transaction]
9
+
10
+ channel_header = build_channel_header Common::HeaderType::ENDORSER_TRANSACTION,
11
+ channel_id, transaction.id, request[:chaincode_id]
12
+ header = build_header channel_header, identity_context.identity, transaction.nonce
13
+ proposal = build_proposal header, request[:chaincode_id], args
14
+ signed_proposal = sign_proposal identity_context.identity, proposal
15
+
16
+ responses = send_peers_process_proposal request[:targets], signed_proposal
17
+
18
+ { responses: responses, proposal: proposal, header: header }
19
+ end
20
+
21
+ private
22
+
23
+ def self.build_header(channel_header, identity, nonce)
24
+ signature_header = Common::SignatureHeader.new creator: identity.serialize,
25
+ nonce: nonce
26
+
27
+ Common::Header.new channel_header: channel_header.to_proto,
28
+ signature_header: signature_header.to_proto
29
+ end
30
+
31
+ def self.build_channel_header(type, channel_id, tx_id, chaincode_id)
32
+ attrs = { type: type, channel_id: channel_id, tx_id: tx_id }
33
+ attrs[:extension] = build_channel_header_extension(chaincode_id).to_proto if chaincode_id
34
+ attrs[:timestamp] = build_current_timestamp
35
+ attrs[:version] = Constants::CHANNEL_HEADER_VERSION
36
+
37
+ Common::ChannelHeader.new attrs
38
+ end
39
+
40
+ def self.build_channel_header_extension(chaincode_id)
41
+ id = Protos::ChaincodeID.new name: chaincode_id
42
+
43
+ Protos::ChaincodeHeaderExtension.new chaincode_id: id
44
+ end
45
+
46
+ def self.build_current_timestamp
47
+ now = Time.current
48
+
49
+ Google::Protobuf::Timestamp.new seconds: now.to_i, nanos: now.sec
50
+ end
51
+
52
+ def self.build_proposal(header, chaincode_id, args)
53
+ chaincode_proposal = build_chaincode_proposal chaincode_id, args
54
+
55
+ Protos::Proposal.new header: header.to_proto,
56
+ payload: chaincode_proposal.to_proto
57
+ end
58
+
59
+ def self.build_chaincode_proposal(chaincode_id, args)
60
+ id = Protos::ChaincodeID.new name: chaincode_id
61
+ chaincode_input = Protos::ChaincodeInput.new args: args
62
+ chaincode_spec = Protos::ChaincodeSpec.new type: Protos::ChaincodeSpec::Type::GOLANG,
63
+ chaincode_id: id,
64
+ input: chaincode_input
65
+ chaincode_invocation_spec =
66
+ Protos::ChaincodeInvocationSpec.new chaincode_spec: chaincode_spec
67
+
68
+ Protos::ChaincodeProposalPayload.new input: chaincode_invocation_spec.to_proto
69
+ end
70
+
71
+ def self.sign_proposal(identity, proposal)
72
+ proposal_bytes = proposal.to_proto
73
+ signature = identity.sign(proposal_bytes)
74
+
75
+ Protos::SignedProposal.new proposal_bytes: proposal_bytes,
76
+ signature: signature
77
+ end
78
+
79
+ def self.send_peers_process_proposal(peers, proposal)
80
+ peers.map do |peer|
81
+ peer.send_process_proposal(proposal)
82
+ end
83
+ end
84
+ end
85
+ end