ethereum.rb 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fed925e12c750f5d20aacd3ac6629f53a9b5f2bd
4
- data.tar.gz: 0bfd128f76455bea9937f82d4d338923d7c6108f
3
+ metadata.gz: be2456e92fe65e0d189e20fe4918441737ec34f9
4
+ data.tar.gz: 2d02debd5fa6c4f521ffb0d12d58d595d5694441
5
5
  SHA512:
6
- metadata.gz: 04f8f2bada3e7ad9862a36793954452ce4a6c7f0244953bac92a6321dd815422a717d67954b9e7b7d7e9a034e543401ad5cb3de430e6886558a10bbaaad267eb
7
- data.tar.gz: 25db0535bd9f92c205e2cbb3b3eaad6da21994893b7431e7192d8ed5bd59698cdd7e0401b0b9d805a2f14a2abf88aea970b4f04dfdffc89be5a3223cb0ec1c50
6
+ metadata.gz: 178e6371e427adf8524a44e5a578207eb581fc4bc7cb987e499c034f5a64340089034358cd2d9bc8054d35dfc8b5bd03fc75b0dc1703f7a8bbbfe6f165e776ec
7
+ data.tar.gz: e9c0fa8ba6f3f28ad908ebf0da7347ea41d5a10b0061b0d37ebc70f62dfd91c4ca3c76ffd5e073758b71fd4805a72a55b391ad19917d37a13b023653d6b91cf4
data/PREREQUISITES.md CHANGED
@@ -2,29 +2,37 @@
2
2
 
3
3
  ## Compatibility and requirements
4
4
 
5
- * Tested with parity 1.5.0, might work with geth (but was not tested)
5
+ * Tested with parity 1.5, might work with geth and older parity, but was not tested.
6
6
  * Tested with solc 0.4.9
7
7
  * Ruby 2.x
8
8
  * UNIX/Linux or OS X environment
9
9
 
10
- ## Prerequisites
11
-
12
- Ethereum.rb requires installation of ethereum node and solidity compiler.
10
+ ## Installing prerequisites
13
11
 
14
12
  ### Ethereum node
15
13
 
16
- Currently the lib supports only [parity](https://ethcore.io/parity.html). To install parity on mac simply:
14
+ Currently the only node supported by ethereum.rb is [parity](https://ethcore.io/parity.html). To install parity on mac simply:
17
15
 
16
+ $ brew tap ethcore/ethcore
18
17
  $ brew install parity --beta
19
18
 
20
19
  To install parity on linux download latest package from [parity github](https://github.com/ethcore/parity/releases) and install on your computer.
21
20
 
22
- It might work with [geth](https://github.com/ethereum/go-ethereum/wiki/geth) as well, but this configuration is not tested. Library assumes that you have at least one wallet configured.
21
+ It might work with [geth](https://github.com/ethereum/go-ethereum/wiki/geth) as well, but this configuration is not tested.
22
+
23
+ To work correctly ethereum.rb needs parity to have at least one wallet configured. Parity should automatically create one for you during installation.
24
+ You can see the list of wallets by calling:
25
+
26
+ $ parity account list
27
+
28
+ And create one with following command:
29
+
30
+ $ parity account new
23
31
 
24
32
  ### Solidity complier
25
33
 
26
34
  To be able to compile [solidity](https://github.com/ethereum/solidity) contracts you need to install solc compiler. Installation instructions are available [here](http://solidity.readthedocs.io/en/latest/installing-solidity.html).
27
- To install on mac simply:
35
+ To install on mac type:
28
36
 
29
37
  $ brew install solidity --beta
30
38
 
@@ -45,3 +53,20 @@ And then execute:
45
53
  Or install it yourself as:
46
54
 
47
55
  $ gem install ethereum.eb
56
+
57
+ ### Running a node
58
+
59
+ There is a rake task to run node on testnet network, that you can run from your application directory:
60
+
61
+ $ rake ethereum:node:test
62
+
63
+ It will run parity node, unlock the first account on the account list, but you need to supply it with password.
64
+ To do that adding create file containing password accessable from your parity folder, which should be one of the following:
65
+ * `/Users/You/AppData/Roaming/Parity/Ethereum` on Windows
66
+ * `/Users/you/Library/Application Support/io.parity.ethereum` on MacOS
67
+ * `/home/you/.local/share/parity` on Linux/Unix
68
+ * `/home/you/.parity` on Linux and MacOS for Parity versions older then 1.5.0
69
+
70
+ Warnning: Running a parity node with unlock wallet is a considerable security risk and should be avoided on production servers. Especially avoid running node with unlocked wallet and enabled json rpc server in http mode.
71
+
72
+ To send transaction on a testnet blockchain you will need test ether, you can get it [here](http://faucet.ropsten.be:3001/).
data/README.md CHANGED
@@ -4,18 +4,27 @@
4
4
 
5
5
  The goal of ethereum.rb is to make interacting with ethereum blockchain from ruby as easy as possible (but not easier).
6
6
 
7
+ Announcement: The Ropsten network is currently being spammed, therefore CI is down and you might have issues to start working with testnet. Use mainnet instead.
8
+
7
9
  ## Highlights
8
10
 
11
+ * Simple syntax, programmer friendly
9
12
  * Deploy and interact with contracts on the blockchain
13
+ * Contract - ruby object mapping
10
14
  * Compile Solidity contracts with solc compiler from ruby
11
- * Receive events from contract
12
- * Run json rpc calls from ruby
15
+ * Receive events from contract
16
+ * Make direct json rpc calls to node from ruby application
13
17
  * Connect to node via IPC or HTTP
14
18
  * Helpful rake tasks for common actions
15
19
 
16
20
  ## Installation
17
21
 
18
- Before installing gem make sure you meet all [prerequisites](https://github.com/marekkirejczyk/ethereum.rb/blob/master/PREREQUISITES.md).
22
+ Before installing gem make sure you meet all [prerequisites](https://github.com/marekkirejczyk/ethereum.rb/blob/master/PREREQUISITES.md), especially that you have:
23
+ * compatible ethereum node installed
24
+ * compatible solidity compiler installed
25
+ * wallet with some ethereum on it
26
+
27
+ Before you run a program check that the node is running and accounts you want to spend from are unlocked.
19
28
 
20
29
  To install gem simply add this line to your application's Gemfile:
21
30
 
@@ -33,125 +42,173 @@ Or install it yourself as:
33
42
 
34
43
  ## Basic Usage
35
44
 
36
- ### Running a node
37
-
38
- Right after parity installation you will have one default account. There is a rake task to run test node, that you can run from your application directory:
39
-
40
- $ rake ethereum:node:test
41
-
42
- It will run parity node, unlock the first account on the account list, but you need to supply it with password. To do that adding create file containing password accessable from the following path:
43
-
44
- `~/.parity/pass`
45
-
46
- To run operations modifiying blockchain you will need test ether, you can get it [here](http://faucet.ropsten.be:3001/).
47
-
48
- ### IPC Client Connection
49
-
50
- To create client instance simply create Ethereum::IpcClient:
45
+ You can create contract from solidity source and deploy it to the blockchain, with following code:
51
46
 
52
47
  ```ruby
53
- client = Ethereum::IpcClient.new
48
+ contract = Ethereum::Contract.create(file: "greeter.sol")
49
+ address = contract.deploy_and_wait("Hello from ethereum.rb!")
54
50
  ```
55
51
 
56
- You can also customize it with path to ipc file path and logging flag:
52
+ Deployment may take up to couple of minutes. Once deployed you can start interacting with contract, e.g. calling it's methods:
57
53
 
58
54
  ```ruby
59
- client = Ethereum::IpcClient.new("~/.parity/mycustom.ipc", false)
55
+ contract.call.greet # => "Hello from ethereum.rb!"
60
56
  ```
61
57
 
62
- If no ipc file path given, IpcClient looks for ipc file in default locations for parity and geth.
63
- By default logging is on and logs are saved in "/tmp/ethereum_ruby_http.log".
58
+ You can see example contract [greeter here](https://github.com/marekkirejczyk/ruby_ethereum_example/blob/master/contracts/greeter.sol).
64
59
 
60
+ ## Creating contract
65
61
 
66
- ### Solidity contract compilation and deployment
67
-
68
- You can create contract from solidity source and deploy it to the blockchain.
69
-
70
- ```ruby
71
- contract = Ethereum::Contract.create(file: "mycontract.sol", client: client)
72
- address = contract.deploy_and_wait
73
- ```
62
+ ### Compile multiple contracts at once
74
63
 
75
- Deployment may take up to couple minutes.
76
- If you want to complie multiple contracts at once, you can create new instances using newly declared clasess:
64
+ If you want to complie multiple contracts at once, you can create new instances using newly declared ruby clasess:
77
65
 
78
66
  ```ruby
79
- Ethereum::Contract.create(file: "mycontract.sol", client: client)
80
- contract = MyContract.new
67
+ Ethereum::Contract.create(file: "mycontracts.sol", client: client)
68
+ contract = MyContract1.new
81
69
  contract = contract.deploy_and_wait
70
+ contract2 = MyContract2.new
71
+ contract2 = contract.deploy_and_wait
82
72
  ```
83
73
 
84
74
  All names used to name contract in solidity source will transalte to name of classes in ruby (camelized).
85
- If class of given name exist it will be undefined first to avoid name collision.
75
+
76
+ Note: If class of given name exist it will be undefined first to avoid name collision.
86
77
 
87
78
  ### Get contract from blockchain
88
79
 
89
- The other way to obtain contract instance is get one form the blockchain. To do so you need a contract name, contract address and ABI definition.
90
- `client` parameter is optional.
80
+ The other way to obtain contract instance is get one that already exist in the blockchain. To do so you need a contract name, contract address and ABI definition.
91
81
 
92
82
  ```ruby
93
- contract = Ethereum::Contract.create(name: "MyContract", address: "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ", abi: abi, client: client)
83
+ contract = Ethereum::Contract.create(name: "MyContract", address: "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ", abi: abi)
94
84
  ```
95
85
 
96
86
  Note that you need to specify contract name, that will be used to define new class in ruby, as it is not a part of ABI definition.
97
87
 
98
- If you want to create new contract, that is not yet deployed from ABI definition you need to supply binary code too:
88
+ Alternatively you can obtain abi definition and name from contract source file:
89
+
90
+ ```ruby
91
+ contract = Ethereum::Contract.create(file: "MyContract.sol", address: "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ")
92
+ ```
93
+
94
+ If you want to create new contract, that is not yet deployed from ABI definition you will need also to supply binary code:
99
95
 
100
96
  ```ruby
101
- contract = Ethereum::Contract.create(name: "MyContract", address: "0x01a4d1A62F01ED966646acBfA8BB0b59960D06dd ", abi: abi, code: "...")
97
+ contract = Ethereum::Contract.create(name: "MyContract", abi: abi, code: "...")
102
98
  ```
103
99
 
104
- ### Transacting and Calling Solidity Functions
100
+ ### Interacting with contract
105
101
 
106
- Functions defined in a contract are exposed using the following conventions:
102
+ Functions defined in a contract are exposed using the following conventions:
107
103
 
108
104
  ```
109
- contract.transact.[function_name](params)
105
+ contract.transact.[function_name](params)
110
106
  contract.transact_and_wait.[function_name](params)
111
107
  contract.call.[function_name](params)
112
108
  ```
113
109
 
114
110
  **Example Contract in Solidity**
115
111
  ```
116
- contract SimpleNameRegistry {
112
+ contract SimpleRegistry {
117
113
 
118
- mapping (address => bool) public myMapping;
114
+ mapping (bytes32 => string) public registry;
119
115
 
120
- function register(address _a, bytes32 _b) {
116
+ function register(bytes32 key, string value) {
117
+ registry[key] = value;
121
118
  }
122
119
 
123
- function getSomeValue(address _x) public constant returns(bool b, address b) {
120
+ function get(bytes32 key) public constant returns(string) {
121
+ return registry[key];
124
122
  }
125
123
 
126
124
  }
127
125
  ```
128
126
 
129
- And here is how to access it's methods:
127
+ For contract above here is how to access it's methods:
128
+
129
+ ```ruby
130
+ contract.transact_and_wait.register("performer", "Beastie Boys")
131
+ ```
132
+
133
+ Will send transaction to the blockchain and wait for it to be mined.
134
+
135
+ ```ruby
136
+ contract.transact.register("performer", "Black Eyed Peas")
137
+ ```
138
+
139
+ Will send transaction to the blockchain return instantly.
140
+
141
+ ```ruby
142
+ contract.call.get("performer") # => "Black Eyed Peas"
143
+ ```
144
+
145
+ Will call method of the contract and return result.
146
+ Note that no transaction need to be send to the network as method is read-only.
147
+ On the other hand `register` method will change contract state, so you need to use `transact` or `transact_and_wait` to call it.
148
+
149
+
150
+ ### IPC Client Connection
151
+
152
+ By default methods interacting with contracts will use default Json RPC Client that will handle connection to ethereum node.
153
+ Default client communicate via IPC. If you want to create custom client or use multiple clients you can create them yourself.
154
+
155
+ To create IPC client instance of simply create Ethereum::IpcClient:
156
+
157
+ ```ruby
158
+ client = Ethereum::IpcClient.new
159
+ ```
160
+
161
+ You can also customize it with path to ipc file path and logging flag:
130
162
 
131
163
  ```ruby
132
- contract.transact_and_wait.register("0x5b6cb65d40b0e27fab87a2180abcab22174a2d45", "minter.contract.dgx")
133
- contract.transact.register("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055", "anthony@eufemio.dgx")
134
- contract.call.get_some_value("0x385acafdb80b71ae001f1dbd0d65e62ec2fff055")
164
+ client = Ethereum::IpcClient.new("~/.parity/mycustom.ipc", false)
135
165
  ```
136
166
 
137
- Note that as `register` method will change contract state, so you need to use `transact` family of methods (or `transact_and_wait` for synchronous version) to call it.
167
+ If no ipc file path given, IpcClient looks for ipc file in default locations for parity and geth.
168
+ The second argument is optional. If it is true then logging is on.
138
169
 
139
- For method like `getSomeValue`, that does not affect state of the contract (and don't need to propagate change to blockchain therefore) you can use call method. It will retrive value from local copy of the blockchain.
170
+ By default logging is on and logs are saved in "/tmp/ethereum_ruby_http.log".
171
+
172
+ To create Http client use following:
173
+
174
+ ```ruby
175
+ client = Ethereum::HttpClient.new('http://localhost:8545')
176
+ ```
140
177
 
178
+ You can supply client when creating a contract:
179
+
180
+ ```ruby
181
+ contract = Ethereum::Contract.create(client: client, ...)
182
+ ```
183
+
184
+ You can also obtain default client:
185
+
186
+ ```ruby
187
+ client = Ethereum::Singleton.instance
188
+ ```
189
+
190
+ ### Calling json rpc methods
191
+
192
+ Ethereum.rb allows you to interact directly with Ethereum node using json rpc api calls.
193
+ Api calls translates directly to client methods. E.g. to call `eth_gasPrice` method:
194
+
195
+ ```ruby
196
+ client.eth_gas_price # => {"jsonrpc"=>"2.0", "result"=>"0x4a817c800", "id"=>1}
197
+ ```
198
+
199
+ Note: methods are transated to underscore notation.
200
+
201
+ Full list of json rpc methods is available [here](https://github.com/ethereum/wiki/wiki/JSON-RPC#user-content-json-rpc-methods)
141
202
 
142
203
  ## Utils rake tasks
143
204
 
144
- There is plenty of useful rake tasks for interacting with blockchain:
205
+ There are couple of rake tasks to help in wallet maintenance, i.e.:
145
206
 
146
207
  ```ruby
147
- rake ethereum:contract:compile[path] # Compile a contract / Compile and deploy contract
148
- rake ethereum:node:mine # Mine ethereum testing environment for ethereum node
149
- rake ethereum:node:run # Run morden (production) node
150
- rake ethereum:node:test # Run testnet node
151
- rake ethereum:test:setup # Setup testing environment for ethereum node
208
+ rake ethereum:contract:deploy[path] # Compile and deploy contract
209
+ rake ethereum:contract:compile[path] # Compile a contract
152
210
  rake ethereum:transaction:byhash[id] # Get info about transaction
153
211
  rake ethereum:transaction:send[address,amount] # Send [amount of] ether to an account
154
-
155
212
  ```
156
213
 
157
214
  ## Debbuging
@@ -162,17 +219,16 @@ Logs from communication between ruby app and node are available under following
162
219
 
163
220
  ## Roadmap
164
221
 
165
- * Dynamic arrays serialization
166
- * Signing transactions
167
-
222
+ * Rubydoc documentation
223
+ * Signing transactions
168
224
 
169
225
  ## Development
170
226
 
171
- Make sure `rake ethereum:test:setup` passes before running tests.
227
+ Run `bin/console` for an interactive prompt that will allow you to experiment.
172
228
 
173
- You can also run `bin/console` for an interactive prompt that will allow you to experiment.
229
+ Make sure `rake ethereum:test:setup` passes before running tests.
174
230
 
175
- Then, run `rake spec` to run the tests.
231
+ Then, run `rake spec` to run the tests.
176
232
 
177
233
  Test that do send transactions to blockchain are marked with `blockchain` tag. Good practice is to run first fast tests that use no ether and only if they pass, run slow tests that do spend ether. To do that use the following line:
178
234
 
@@ -185,4 +241,3 @@ You need ethereum node up and running for tests to pass and it needs to be worki
185
241
  This library has been forked from [ethereum-ruby](https://github.com/DigixGlobal/ethereum-ruby) by DigixGlobal Pte Ltd (https://dgx.io).
186
242
 
187
243
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
188
-
@@ -48,46 +48,38 @@ module Ethereum
48
48
  @default_account || eth_accounts["result"][0]
49
49
  end
50
50
 
51
- def int_to_hex(n)
52
- return "0x#{n.to_s(16)}"
51
+ def int_to_hex(p)
52
+ p.is_a?(Integer) ? "0x#{p.to_s(16)}" : p
53
53
  end
54
54
 
55
- # https://github.com/ethereum/wiki/wiki/JSON-RPC#output-hex-values
56
55
  def encode_params(params)
57
- return params.map do |p|
58
- if p.is_a?(Integer)
59
- int_to_hex(p)
60
- else
61
- p
62
- end
56
+ params.map(&method(:int_to_hex))
57
+ end
58
+
59
+ def send_command(command,args)
60
+ if ["eth_getBalance", "eth_call"].include?(command)
61
+ args << "latest"
62
+ end
63
+
64
+ payload = {jsonrpc: "2.0", method: command, params: encode_params(args), id: get_id}
65
+
66
+ @logger.info("Sending #{payload.to_json}") if @log
67
+
68
+ if @batch
69
+ @batch << payload
70
+ return true
71
+ else
72
+ output = JSON.parse(send_single(payload.to_json))
73
+ @logger.info("Received #{output.to_json}") if @log
74
+ reset_id
75
+ return output
63
76
  end
64
77
  end
65
78
 
66
79
  (RPC_COMMANDS + RPC_MANAGEMENT_COMMANDS).each do |rpc_command|
67
80
  method_name = rpc_command.underscore
68
81
  define_method method_name do |*args|
69
- command = rpc_command
70
- if ["eth_getBalance", "eth_call"].include?(command)
71
- args << "latest"
72
- end
73
- payload = {jsonrpc: "2.0", method: command, params: encode_params(args), id: get_id}
74
-
75
- if @log == true
76
- @logger.info("Sending #{payload.to_json}")
77
- end
78
-
79
- if @batch
80
- @batch << payload
81
- return true
82
- else
83
- read = send_single(payload.to_json)
84
- output = JSON.parse(read)
85
- if @log == true
86
- @logger.info("Received #{output.to_json}")
87
- end
88
- reset_id
89
- return output
90
- end
82
+ send_command(rpc_command, args)
91
83
  end
92
84
  end
93
85
 
@@ -16,13 +16,13 @@ module Ethereum
16
16
  end
17
17
 
18
18
  def decode_static_array(arity, array_subtype, value, start)
19
- (1..arity).map.with_index { |e, i| decode(array_subtype, value, start + i * 64) }
19
+ (0..arity-1).map { |i| decode(array_subtype, value, start + i * 64) }
20
20
  end
21
21
 
22
22
  def decode_dynamic_array(array_subtype, value, start)
23
23
  location = decode_uint(value[start..(start+63)]) * 2
24
24
  size = decode_uint(value[location..location+63])
25
- (1..size).map.with_index { |e, i| decode(array_subtype, value, location + (i+1) * 64) }
25
+ (0..size-1).map { |i| decode(array_subtype, value, location + (i+1) * 64) }
26
26
  end
27
27
 
28
28
  def decode_fixed(value, subtype = "128x128", start = 0)
@@ -85,7 +85,7 @@ module Ethereum
85
85
  subtype.present? ? subtype.to_i : default
86
86
  end
87
87
 
88
- def fixed_bitsize(subtype = nil, default = 256)
88
+ def fixed_bitsize(subtype = nil)
89
89
  subtype ||= "128x128"
90
90
  _, x, n = /(\d+)x(\d+)/.match(subtype).to_a
91
91
  x.to_i + n.to_i
@@ -16,13 +16,14 @@ module Ethereum
16
16
  end
17
17
 
18
18
  def encode_static_array(arity, array_subtype, array)
19
- (1..arity).map.with_index { |e, i| encode(array_subtype, array[i]) }.join
19
+ raise "Wrong number of arguments" if arity != array.size
20
+ array.inject("") { |a, e| a << encode(array_subtype, e) }
20
21
  end
21
22
 
22
23
  def encode_dynamic_array(array_subtype, array)
23
24
  location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
24
25
  size = encode_uint(array.size)
25
- data = (1..array.size).map.with_index { |e, i| encode(array_subtype, array[i]) }.join
26
+ data = array.inject("") { |a, e| a << encode(array_subtype, e) }
26
27
  [location, size + data]
27
28
  end
28
29
 
@@ -4,6 +4,8 @@ module Ethereum
4
4
  rake_tasks do
5
5
  load('tasks/ethereum_test.rake')
6
6
  load('tasks/ethereum_node.rake')
7
+ load('tasks/ethereum_contract.rake')
8
+ load('tasks/ethereum_transaction.rake')
7
9
  end
8
10
  end
9
11
 
@@ -19,8 +19,8 @@ module Ethereum
19
19
 
20
20
  def compile(filename)
21
21
  result = {}
22
- execute_solc(nil, filename).scan(OUTPUT_REGEXP).each do |match|
23
- file, name, bin, abi = match
22
+ execute_solc(filename).scan(OUTPUT_REGEXP).each do |match|
23
+ _file, name, bin, abi = match
24
24
  result[name] = {}
25
25
  result[name]["abi"] = abi
26
26
  result[name]["bin"] = bin
@@ -29,7 +29,7 @@ module Ethereum
29
29
  end
30
30
 
31
31
  private
32
- def execute_solc(dir, filename)
32
+ def execute_solc(filename)
33
33
  cmd = "#{@bin_path} #{@args} '#{filename}'"
34
34
  out, stderr, status = Open3.capture3(cmd)
35
35
  raise SystemCallError, "Unanable to run solc compliers" if status.exitstatus == 127
@@ -1,3 +1,3 @@
1
1
  module Ethereum
2
- VERSION = "2.0.4"
2
+ VERSION = "2.0.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ethereum.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marek Kirejczyk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-05 00:00:00.000000000 Z
11
+ date: 2017-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -195,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
195
  version: '0'
196
196
  requirements: []
197
197
  rubyforge_project:
198
- rubygems_version: 2.5.1
198
+ rubygems_version: 2.6.8
199
199
  signing_key:
200
200
  specification_version: 4
201
201
  summary: Ruby Ethereum client using the JSON-RPC interface