flow_client 0.1.0

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +35 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +20 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/Gemfile +14 -0
  9. data/Gemfile.lock +115 -0
  10. data/Guardfile +79 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +93 -0
  13. data/Rakefile +12 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/flow_client.gemspec +44 -0
  17. data/lib/flow/access/access_pb.rb +168 -0
  18. data/lib/flow/access/access_services_pb.rb +96 -0
  19. data/lib/flow/entities/account_pb.rb +30 -0
  20. data/lib/flow/entities/block_header_pb.rb +20 -0
  21. data/lib/flow/entities/block_pb.rb +25 -0
  22. data/lib/flow/entities/block_seal_pb.rb +19 -0
  23. data/lib/flow/entities/collection_pb.rb +23 -0
  24. data/lib/flow/entities/event_pb.rb +20 -0
  25. data/lib/flow/entities/transaction_pb.rb +47 -0
  26. data/lib/flow/execution/execution_pb.rb +65 -0
  27. data/lib/flow/execution/execution_services_pb.rb +43 -0
  28. data/lib/flow/legacy/access/access_pb.rb +157 -0
  29. data/lib/flow/legacy/access/access_services_pb.rb +89 -0
  30. data/lib/flow/legacy/entities/account_pb.rb +28 -0
  31. data/lib/flow/legacy/entities/block_header_pb.rb +20 -0
  32. data/lib/flow/legacy/entities/block_pb.rb +25 -0
  33. data/lib/flow/legacy/entities/block_seal_pb.rb +19 -0
  34. data/lib/flow/legacy/entities/collection_pb.rb +22 -0
  35. data/lib/flow/legacy/entities/event_pb.rb +20 -0
  36. data/lib/flow/legacy/entities/transaction_pb.rb +45 -0
  37. data/lib/flow/legacy/execution/execution_pb.rb +65 -0
  38. data/lib/flow/legacy/execution/execution_services_pb.rb +42 -0
  39. data/lib/flow_client.rb +14 -0
  40. data/lib/flow_client/client.rb +98 -0
  41. data/lib/flow_client/crypto.rb +33 -0
  42. data/lib/flow_client/transaction.rb +147 -0
  43. data/lib/flow_client/utils.rb +38 -0
  44. data/lib/flow_client/version.rb +5 -0
  45. metadata +201 -0
@@ -0,0 +1,28 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/account.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("flow/legacy/entities/account.proto", :syntax => :proto3) do
8
+ add_message "entities.Account" do
9
+ optional :address, :bytes, 1
10
+ optional :balance, :uint64, 2
11
+ optional :code, :bytes, 3
12
+ repeated :keys, :message, 4, "entities.AccountKey"
13
+ end
14
+ add_message "entities.AccountKey" do
15
+ optional :index, :uint32, 1
16
+ optional :public_key, :bytes, 2
17
+ optional :sign_algo, :uint32, 3
18
+ optional :hash_algo, :uint32, 4
19
+ optional :weight, :uint32, 5
20
+ optional :sequence_number, :uint32, 6
21
+ end
22
+ end
23
+ end
24
+
25
+ module Entities
26
+ Account = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Account").msgclass
27
+ AccountKey = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.AccountKey").msgclass
28
+ end
@@ -0,0 +1,20 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/block_header.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ require 'google/protobuf/timestamp_pb'
7
+ Google::Protobuf::DescriptorPool.generated_pool.build do
8
+ add_file("flow/legacy/entities/block_header.proto", :syntax => :proto3) do
9
+ add_message "entities.BlockHeader" do
10
+ optional :id, :bytes, 1
11
+ optional :parent_id, :bytes, 2
12
+ optional :height, :uint64, 3
13
+ optional :timestamp, :message, 4, "google.protobuf.Timestamp"
14
+ end
15
+ end
16
+ end
17
+
18
+ module Entities
19
+ BlockHeader = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.BlockHeader").msgclass
20
+ end
@@ -0,0 +1,25 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/block.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ require 'google/protobuf/timestamp_pb'
7
+ require 'flow/legacy/entities/collection_pb'
8
+ require 'flow/legacy/entities/block_seal_pb'
9
+ Google::Protobuf::DescriptorPool.generated_pool.build do
10
+ add_file("flow/legacy/entities/block.proto", :syntax => :proto3) do
11
+ add_message "entities.Block" do
12
+ optional :id, :bytes, 1
13
+ optional :parent_id, :bytes, 2
14
+ optional :height, :uint64, 3
15
+ optional :timestamp, :message, 4, "google.protobuf.Timestamp"
16
+ repeated :collection_guarantees, :message, 5, "entities.CollectionGuarantee"
17
+ repeated :block_seals, :message, 6, "entities.BlockSeal"
18
+ repeated :signatures, :bytes, 7
19
+ end
20
+ end
21
+ end
22
+
23
+ module Entities
24
+ Block = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Block").msgclass
25
+ end
@@ -0,0 +1,19 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/block_seal.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("flow/legacy/entities/block_seal.proto", :syntax => :proto3) do
8
+ add_message "entities.BlockSeal" do
9
+ optional :block_id, :bytes, 1
10
+ optional :execution_receipt_id, :bytes, 2
11
+ repeated :execution_receipt_signatures, :bytes, 3
12
+ repeated :result_approval_signatures, :bytes, 4
13
+ end
14
+ end
15
+ end
16
+
17
+ module Entities
18
+ BlockSeal = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.BlockSeal").msgclass
19
+ end
@@ -0,0 +1,22 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/collection.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("flow/legacy/entities/collection.proto", :syntax => :proto3) do
8
+ add_message "entities.Collection" do
9
+ optional :id, :bytes, 1
10
+ repeated :transaction_ids, :bytes, 2
11
+ end
12
+ add_message "entities.CollectionGuarantee" do
13
+ optional :collection_id, :bytes, 1
14
+ repeated :signatures, :bytes, 2
15
+ end
16
+ end
17
+ end
18
+
19
+ module Entities
20
+ Collection = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Collection").msgclass
21
+ CollectionGuarantee = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.CollectionGuarantee").msgclass
22
+ end
@@ -0,0 +1,20 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/event.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("flow/legacy/entities/event.proto", :syntax => :proto3) do
8
+ add_message "entities.Event" do
9
+ optional :type, :string, 1
10
+ optional :transaction_id, :bytes, 2
11
+ optional :transaction_index, :uint32, 3
12
+ optional :event_index, :uint32, 4
13
+ optional :payload, :bytes, 5
14
+ end
15
+ end
16
+ end
17
+
18
+ module Entities
19
+ Event = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Event").msgclass
20
+ end
@@ -0,0 +1,45 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/entities/transaction.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("flow/legacy/entities/transaction.proto", :syntax => :proto3) do
8
+ add_message "entities.Transaction" do
9
+ optional :script, :bytes, 1
10
+ repeated :arguments, :bytes, 2
11
+ optional :reference_block_id, :bytes, 3
12
+ optional :gas_limit, :uint64, 4
13
+ optional :proposal_key, :message, 5, "entities.Transaction.ProposalKey"
14
+ optional :payer, :bytes, 6
15
+ repeated :authorizers, :bytes, 7
16
+ repeated :payload_signatures, :message, 8, "entities.Transaction.Signature"
17
+ repeated :envelope_signatures, :message, 9, "entities.Transaction.Signature"
18
+ end
19
+ add_message "entities.Transaction.ProposalKey" do
20
+ optional :address, :bytes, 1
21
+ optional :key_id, :uint32, 2
22
+ optional :sequence_number, :uint64, 3
23
+ end
24
+ add_message "entities.Transaction.Signature" do
25
+ optional :address, :bytes, 1
26
+ optional :key_id, :uint32, 2
27
+ optional :signature, :bytes, 3
28
+ end
29
+ add_enum "entities.TransactionStatus" do
30
+ value :UNKNOWN, 0
31
+ value :PENDING, 1
32
+ value :FINALIZED, 2
33
+ value :EXECUTED, 3
34
+ value :SEALED, 4
35
+ value :EXPIRED, 5
36
+ end
37
+ end
38
+ end
39
+
40
+ module Entities
41
+ Transaction = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Transaction").msgclass
42
+ Transaction::ProposalKey = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Transaction.ProposalKey").msgclass
43
+ Transaction::Signature = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.Transaction.Signature").msgclass
44
+ TransactionStatus = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("entities.TransactionStatus").enummodule
45
+ end
@@ -0,0 +1,65 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: flow/legacy/execution/execution.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ require 'flow/legacy/entities/account_pb'
7
+ require 'flow/legacy/entities/event_pb'
8
+ Google::Protobuf::DescriptorPool.generated_pool.build do
9
+ add_file("flow/legacy/execution/execution.proto", :syntax => :proto3) do
10
+ add_message "execution.PingRequest" do
11
+ end
12
+ add_message "execution.PingResponse" do
13
+ end
14
+ add_message "execution.GetAccountAtBlockIDRequest" do
15
+ optional :block_id, :bytes, 1
16
+ optional :address, :bytes, 2
17
+ end
18
+ add_message "execution.GetAccountAtBlockIDResponse" do
19
+ optional :account, :message, 1, "entities.Account"
20
+ end
21
+ add_message "execution.ExecuteScriptAtBlockIDRequest" do
22
+ optional :block_id, :bytes, 1
23
+ optional :script, :bytes, 2
24
+ repeated :arguments, :bytes, 3
25
+ end
26
+ add_message "execution.ExecuteScriptAtBlockIDResponse" do
27
+ optional :value, :bytes, 1
28
+ end
29
+ add_message "execution.GetEventsForBlockIDsResponse" do
30
+ repeated :results, :message, 1, "execution.GetEventsForBlockIDsResponse.Result"
31
+ end
32
+ add_message "execution.GetEventsForBlockIDsResponse.Result" do
33
+ optional :block_id, :bytes, 1
34
+ optional :block_height, :uint64, 2
35
+ repeated :events, :message, 3, "entities.Event"
36
+ end
37
+ add_message "execution.GetEventsForBlockIDsRequest" do
38
+ optional :type, :string, 1
39
+ repeated :block_ids, :bytes, 2
40
+ end
41
+ add_message "execution.GetTransactionResultRequest" do
42
+ optional :block_id, :bytes, 1
43
+ optional :transaction_id, :bytes, 2
44
+ end
45
+ add_message "execution.GetTransactionResultResponse" do
46
+ optional :status_code, :uint32, 1
47
+ optional :error_message, :string, 2
48
+ repeated :events, :message, 3, "entities.Event"
49
+ end
50
+ end
51
+ end
52
+
53
+ module Execution
54
+ PingRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.PingRequest").msgclass
55
+ PingResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.PingResponse").msgclass
56
+ GetAccountAtBlockIDRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetAccountAtBlockIDRequest").msgclass
57
+ GetAccountAtBlockIDResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetAccountAtBlockIDResponse").msgclass
58
+ ExecuteScriptAtBlockIDRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.ExecuteScriptAtBlockIDRequest").msgclass
59
+ ExecuteScriptAtBlockIDResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.ExecuteScriptAtBlockIDResponse").msgclass
60
+ GetEventsForBlockIDsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetEventsForBlockIDsResponse").msgclass
61
+ GetEventsForBlockIDsResponse::Result = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetEventsForBlockIDsResponse.Result").msgclass
62
+ GetEventsForBlockIDsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetEventsForBlockIDsRequest").msgclass
63
+ GetTransactionResultRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetTransactionResultRequest").msgclass
64
+ GetTransactionResultResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("execution.GetTransactionResultResponse").msgclass
65
+ end
@@ -0,0 +1,42 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: flow/legacy/execution/execution.proto for package 'execution'
3
+
4
+ require 'grpc'
5
+ require 'flow/legacy/execution/execution_pb'
6
+
7
+ module Execution
8
+ module ExecutionAPI
9
+ # ExecutionAPI is the API provided by the execution nodes.
10
+ class Service
11
+
12
+ include ::GRPC::GenericService
13
+
14
+ self.marshal_class_method = :encode
15
+ self.unmarshal_class_method = :decode
16
+ self.service_name = 'execution.ExecutionAPI'
17
+
18
+ # Ping is used to check if the access node is alive and healthy.
19
+ rpc :Ping, ::Execution::PingRequest, ::Execution::PingResponse
20
+ # Accounts
21
+ #
22
+ # GetAccountAtBlockID gets an account by address at the given block ID
23
+ rpc :GetAccountAtBlockID, ::Execution::GetAccountAtBlockIDRequest, ::Execution::GetAccountAtBlockIDResponse
24
+ # Scripts
25
+ #
26
+ # ExecuteScriptAtBlockID executes a ready-only Cadence script against the
27
+ # execution state at the block with the given ID.
28
+ rpc :ExecuteScriptAtBlockID, ::Execution::ExecuteScriptAtBlockIDRequest, ::Execution::ExecuteScriptAtBlockIDResponse
29
+ # Events
30
+ #
31
+ # GetEventsForBlockIDs retrieves events for all the specified block IDs that
32
+ # have the given type
33
+ rpc :GetEventsForBlockIDs, ::Execution::GetEventsForBlockIDsRequest, ::Execution::GetEventsForBlockIDsResponse
34
+ # Transaction
35
+ #
36
+ # GetTransactionResult gets the result of a transaction.
37
+ rpc :GetTransactionResult, ::Execution::GetTransactionResultRequest, ::Execution::GetTransactionResultResponse
38
+ end
39
+
40
+ Stub = Service.rpc_stub_class
41
+ end
42
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "flow_client/version"
4
+ require "openssl"
5
+ require "rlp"
6
+
7
+ # Collection of classes to interact with the Flow blockchain
8
+ module FlowClient
9
+ class Error < StandardError; end
10
+ require "flow_client/crypto"
11
+ require "flow_client/utils"
12
+ require "flow_client/client"
13
+ require "flow_client/transaction"
14
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "flow/access/access_services_pb"
4
+ require "flow/execution/execution_services_pb"
5
+ require "json"
6
+
7
+ # Collection of classes to interact with the Flow blockchain
8
+ module FlowClient
9
+ # Flow client
10
+ class Client
11
+ attr_accessor :address_aliases
12
+
13
+ def initialize(node_address)
14
+ @stub = Access::AccessAPI::Stub.new(node_address, :this_channel_is_insecure)
15
+ @address_aliases = {}
16
+ end
17
+
18
+ def ping
19
+ req = Access::PingRequest.new
20
+ @stub.ping(req)
21
+ end
22
+
23
+ # Accounts
24
+ def get_account(address)
25
+ req = Access::GetAccountAtLatestBlockRequest.new(address: to_bytes(address))
26
+ res = @stub.get_account_at_latest_block(req)
27
+ res.account
28
+ end
29
+
30
+ # Scripts
31
+ def execute_script(script, args = [])
32
+ req = Access::ExecuteScriptAtLatestBlockRequest.new(
33
+ script: FlowClient::Utils.substitute_address_aliases(script, @address_aliases),
34
+ arguments: args
35
+ )
36
+ res = @stub.execute_script_at_latest_block(req)
37
+ parse_json(res.value)
38
+ end
39
+
40
+ # Blocks
41
+ def get_latest_block(is_sealed: true)
42
+ req = Access::GetLatestBlockRequest.new(
43
+ is_sealed: is_sealed
44
+ )
45
+
46
+ @stub.get_latest_block(req)
47
+ end
48
+
49
+ # Events
50
+ def get_events(type, start_height, end_height)
51
+ req = Access::GetEventsForHeightRangeRequest.new(
52
+ type: type,
53
+ start_height: start_height,
54
+ end_height: end_height
55
+ )
56
+ @stub.get_events_for_height_range(req)
57
+ end
58
+
59
+ # Transactions
60
+
61
+ # Send a FlowClient::Transaction transaction to the blockchain
62
+ def send_transaction(transaction)
63
+ transaction.address_aliases = @address_aliases
64
+ req = Access::SendTransactionRequest.new(
65
+ transaction: transaction.message
66
+ )
67
+ @stub.send_transaction(req)
68
+ end
69
+
70
+ def get_transaction(transaction_id)
71
+ req = Access::GetTransactionRequest.new(
72
+ id: to_bytes(transaction_id)
73
+ )
74
+ @stub.get_transaction(req)
75
+ end
76
+
77
+ def get_transaction_result(transaction_id)
78
+ req = Access::GetTransactionRequest.new(
79
+ id: to_bytes(transaction_id)
80
+ )
81
+ @stub.get_transaction_result(req)
82
+ end
83
+
84
+ private
85
+
86
+ def parse_json(event_payload)
87
+ JSON.parse(event_payload, object_class: OpenStruct)
88
+ end
89
+
90
+ def to_bytes(string)
91
+ [string].pack("H*")
92
+ end
93
+
94
+ def to_string(bytes)
95
+ bytes.unpack1("H*")
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module FlowClient
6
+ class Crypto
7
+ def self.sign(data, key)
8
+ digest = OpenSSL::Digest.digest("SHA3-256", data)
9
+ asn = key.dsa_sign_asn1(digest)
10
+ asn1 = OpenSSL::ASN1.decode(asn)
11
+ r, s = asn1.value
12
+ combined_bytes = Utils.left_pad_bytes([r.value.to_s(16)].pack("H*").unpack("C*"), 32) +
13
+ Utils.left_pad_bytes([s.value.to_s(16)].pack("H*").unpack("C*"), 32)
14
+ combined_bytes.pack("C*")
15
+ end
16
+
17
+ # TODO: Handle both sig algos here
18
+ # secp256k1
19
+ # prime256v1
20
+ def self.key_from_hex_keys(private_hex, public_hex)
21
+ asn1 = OpenSSL::ASN1::Sequence(
22
+ [
23
+ OpenSSL::ASN1::Integer(1),
24
+ OpenSSL::ASN1::OctetString([private_hex].pack("H*")),
25
+ OpenSSL::ASN1::ObjectId("prime256v1", 0, :EXPLICIT),
26
+ OpenSSL::ASN1::BitString([public_hex].pack("H*"), 1, :EXPLICIT)
27
+ ]
28
+ )
29
+
30
+ OpenSSL::PKey::EC.new(asn1.to_der)
31
+ end
32
+ end
33
+ end