eth 0.5.0 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/codeql.yml +4 -0
- data/.github/workflows/spec.yml +14 -3
- data/.yardopts +1 -0
- data/AUTHORS.txt +14 -1
- data/CHANGELOG.md +63 -13
- data/README.md +121 -18
- data/bin/console +2 -1
- data/bin/setup +3 -4
- data/codecov.yml +6 -0
- data/eth.gemspec +5 -7
- data/lib/eth/abi/event.rb +137 -0
- data/lib/eth/abi/type.rb +8 -7
- data/lib/eth/abi.rb +29 -11
- data/lib/eth/address.rb +12 -5
- data/lib/eth/api.rb +223 -0
- data/lib/eth/chain.rb +31 -28
- data/lib/eth/client/http.rb +63 -0
- data/lib/eth/client/ipc.rb +50 -0
- data/lib/eth/client.rb +468 -0
- data/lib/eth/constant.rb +71 -0
- data/lib/eth/contract/event.rb +41 -0
- data/lib/eth/contract/function.rb +56 -0
- data/lib/eth/contract/function_input.rb +36 -0
- data/lib/eth/contract/function_output.rb +32 -0
- data/lib/eth/contract/initializer.rb +46 -0
- data/lib/eth/contract.rb +120 -0
- data/lib/eth/eip712.rb +2 -2
- data/lib/eth/key/decrypter.rb +16 -13
- data/lib/eth/key/encrypter.rb +27 -25
- data/lib/eth/key.rb +21 -16
- data/lib/eth/rlp/decoder.rb +114 -0
- data/lib/eth/rlp/encoder.rb +78 -0
- data/lib/eth/rlp/sedes/big_endian_int.rb +66 -0
- data/lib/eth/rlp/sedes/binary.rb +97 -0
- data/lib/eth/rlp/sedes/list.rb +84 -0
- data/lib/eth/rlp/sedes.rb +74 -0
- data/lib/eth/rlp.rb +63 -0
- data/lib/eth/signature.rb +11 -8
- data/lib/eth/solidity.rb +75 -0
- data/lib/eth/tx/eip1559.rb +22 -14
- data/lib/eth/tx/eip2930.rb +23 -15
- data/lib/eth/tx/legacy.rb +14 -10
- data/lib/eth/tx.rb +28 -34
- data/lib/eth/unit.rb +1 -1
- data/lib/eth/util.rb +68 -11
- data/lib/eth/version.rb +3 -3
- data/lib/eth.rb +15 -2
- metadata +31 -23
- data/lib/eth/abi/constant.rb +0 -63
@@ -0,0 +1,36 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
# Provide classes for contract function input.
|
20
|
+
class Contract::FunctionInput
|
21
|
+
attr_accessor :type, :name
|
22
|
+
|
23
|
+
# Constructor of the {Eth::Contract::FunctionInput} class.
|
24
|
+
#
|
25
|
+
# @param data [Hash] contract abi data.
|
26
|
+
def initialize(data)
|
27
|
+
@type = Eth::Abi::Type.parse(data["type"])
|
28
|
+
@name = data["name"]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns types like uint256
|
32
|
+
def type
|
33
|
+
@type.base_type + @type.sub_type
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
# Provide classes for contract function output.
|
20
|
+
class Contract::FunctionOutput
|
21
|
+
attr_accessor :type, :name
|
22
|
+
|
23
|
+
def initialize(data)
|
24
|
+
@type = Eth::Abi::Type.parse(data["type"])
|
25
|
+
@name = data["name"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
@type.base_type + @type.sub_type
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
# Provide classes for contract initializer.
|
20
|
+
class Contract::Initializer
|
21
|
+
attr_accessor :contracts, :file
|
22
|
+
|
23
|
+
# Constructor of the {Eth::Contract::Initializer} class.
|
24
|
+
#
|
25
|
+
# @param file [String] file path to solidity code.
|
26
|
+
def initialize(file)
|
27
|
+
sol_output = Eth::Solidity.new.compile(file)
|
28
|
+
contracts = sol_output.keys
|
29
|
+
|
30
|
+
@contracts = []
|
31
|
+
contracts.each do |contract|
|
32
|
+
abi = sol_output[contract]["abi"]
|
33
|
+
name = contract
|
34
|
+
code = sol_output[contract]["bin"]
|
35
|
+
@contracts << Contract.new(name, code, abi)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Build and return all contracts.
|
40
|
+
def build_all
|
41
|
+
@contracts.each do |contract|
|
42
|
+
contract.build
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/eth/contract.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
|
20
|
+
# Provides classes to access smart contracts
|
21
|
+
class Contract
|
22
|
+
attr_reader :address
|
23
|
+
attr_accessor :key
|
24
|
+
attr_accessor :gas_limit, :gas_price, :max_fee_per_gas, :max_priority_fee_per_gas, :nonce
|
25
|
+
attr_accessor :bin, :name, :abi, :class_object
|
26
|
+
attr_accessor :events, :functions, :constructor_inputs
|
27
|
+
|
28
|
+
# Constructor of the {Eth::Contract} class.
|
29
|
+
#
|
30
|
+
# @param name [String] contract name.
|
31
|
+
# @param bin [String] contract bin string.
|
32
|
+
# @param abi [String] contract abi string.
|
33
|
+
def initialize(name, bin, abi)
|
34
|
+
@name = name
|
35
|
+
@bin = bin
|
36
|
+
@abi = abi
|
37
|
+
@constructor_inputs, @functions, @events = parse_abi(abi)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Creates a contract wrapper.
|
41
|
+
#
|
42
|
+
# @param file [String] solidity file path.
|
43
|
+
# @param bin [String] contract bin string.
|
44
|
+
# @param abi [String] contract abi string.
|
45
|
+
# @param address [String] contract address.
|
46
|
+
# @param name [String] name of contract.
|
47
|
+
# @param contract_index [Number] specify contract.
|
48
|
+
# @return [Eth::Contract::Object] Returns the class of the smart contract.
|
49
|
+
# @raise [JSON::ParserError] if the json format is wrong.
|
50
|
+
# @raise [ArgumentError] if argument is incorrect.
|
51
|
+
def self.create(file: nil, bin: nil, abi: nil, address: nil, name: nil, contract_index: nil)
|
52
|
+
if File.exist?(file.to_s)
|
53
|
+
contracts = Eth::Contract::Initializer.new(file).build_all
|
54
|
+
raise "No contracts compiled" if contracts.empty?
|
55
|
+
if contract_index
|
56
|
+
contract = contracts[contract_index].class_object.new
|
57
|
+
else
|
58
|
+
contract = contracts.first.class_object.new
|
59
|
+
end
|
60
|
+
elsif ![name, bin, abi].include? nil
|
61
|
+
begin
|
62
|
+
abi = abi.is_a?(Array) ? abi : JSON.parse(abi)
|
63
|
+
rescue JSON::ParserError => e
|
64
|
+
raise e
|
65
|
+
end
|
66
|
+
contract = Eth::Contract.new(name, bin, abi)
|
67
|
+
contract.build
|
68
|
+
contract = contract.class_object.new
|
69
|
+
else
|
70
|
+
raise ArgumentError, "The argument is incorrect."
|
71
|
+
end
|
72
|
+
contract.address = address
|
73
|
+
contract
|
74
|
+
end
|
75
|
+
|
76
|
+
# Set the address of the smart contract
|
77
|
+
def address=(addr)
|
78
|
+
@address = addr.nil? ? nil : Eth::Address.new(addr).address
|
79
|
+
@events.each do |event|
|
80
|
+
event.set_address(@address)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create classes for smart contracts
|
85
|
+
def build
|
86
|
+
class_name = @name
|
87
|
+
parent = self
|
88
|
+
class_methods = Class.new do
|
89
|
+
extend Forwardable
|
90
|
+
def_delegators :parent, :key, :key=
|
91
|
+
def_delegators :parent, :name, :abi, :bin
|
92
|
+
def_delegators :parent, :gas_limit, :gas_price, :gas_limit=, :gas_price=, :nonce, :nonce=
|
93
|
+
def_delegators :parent, :max_fee_per_gas, :max_fee_per_gas=, :max_priority_fee_per_gas, :max_priority_fee_per_gas=
|
94
|
+
def_delegators :parent, :events
|
95
|
+
def_delegators :parent, :address, :address=
|
96
|
+
def_delegator :parent, :functions
|
97
|
+
define_method :parent do
|
98
|
+
parent
|
99
|
+
end
|
100
|
+
end
|
101
|
+
Eth::Contract.send(:remove_const, class_name) if Eth::Contract.const_defined?(class_name, false)
|
102
|
+
Eth::Contract.const_set(class_name, class_methods)
|
103
|
+
@class_object = class_methods
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def parse_abi(abi)
|
109
|
+
constructor = abi.detect { |x| x["type"] == "constructor" }
|
110
|
+
if !constructor.nil?
|
111
|
+
constructor_inputs = constructor["inputs"].map { |input| Eth::Contract::FunctionInput.new(input) }
|
112
|
+
else
|
113
|
+
constructor_inputs = []
|
114
|
+
end
|
115
|
+
functions = abi.select { |x| x["type"] == "function" }.map { |fun| Eth::Contract::Function.new(fun) }
|
116
|
+
events = abi.select { |x| x["type"] == "event" }.map { |evt| Eth::Contract::Event.new(evt) }
|
117
|
+
[constructor_inputs, functions, events]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/eth/eip712.rb
CHANGED
@@ -12,11 +12,11 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# Provides the
|
15
|
+
# Provides the {Eth} module.
|
16
16
|
module Eth
|
17
17
|
|
18
18
|
# Defines handy tools for encoding typed structured data as per EIP-712.
|
19
|
-
#
|
19
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-712
|
20
20
|
module Eip712
|
21
21
|
extend self
|
22
22
|
|
data/lib/eth/key/decrypter.rb
CHANGED
@@ -12,37 +12,40 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# Provides the
|
15
|
+
# Provides the {Eth} module.
|
16
16
|
module Eth
|
17
17
|
|
18
|
-
# The Eth::Key::Decrypter class to handle PBKDF2-SHA-256 decryption.
|
18
|
+
# The {Eth::Key::Decrypter} class to handle PBKDF2-SHA-256 decryption.
|
19
19
|
class Key::Decrypter
|
20
20
|
|
21
21
|
# Provides a specific decrypter error if decryption fails.
|
22
22
|
class DecrypterError < StandardError; end
|
23
23
|
|
24
|
-
# Class method
|
24
|
+
# Class method {Eth::Key::Decrypter.perform} to perform an keystore
|
25
|
+
# decryption.
|
25
26
|
#
|
26
|
-
# @param data [JSON] encryption data including cypherkey
|
27
|
-
# @param password [String] password to decrypt the key
|
28
|
-
# @return [Eth::Key] decrypted key-pair
|
27
|
+
# @param data [JSON] encryption data including cypherkey.
|
28
|
+
# @param password [String] password to decrypt the key.
|
29
|
+
# @return [Eth::Key] decrypted key-pair.
|
29
30
|
def self.perform(data, password)
|
30
31
|
new(data, password).perform
|
31
32
|
end
|
32
33
|
|
33
|
-
# Constructor of the
|
34
|
-
#
|
34
|
+
# Constructor of the {Eth::Key::Decrypter} class for secret key
|
35
|
+
# decryption. Should not be used; use {Eth::Key::Decrypter.perform}
|
36
|
+
# instead.
|
35
37
|
#
|
36
|
-
# @param data [JSON] encryption data including cypherkey
|
37
|
-
# @param password [String] password to decrypt the key
|
38
|
+
# @param data [JSON] encryption data including cypherkey.
|
39
|
+
# @param password [String] password to decrypt the key.
|
38
40
|
def initialize(data, password)
|
39
|
-
|
41
|
+
data = JSON.parse(data) if data.is_a? String
|
42
|
+
@data = data
|
40
43
|
@password = password
|
41
44
|
end
|
42
45
|
|
43
|
-
# Method to decrypt key using password
|
46
|
+
# Method to decrypt key using password.
|
44
47
|
#
|
45
|
-
# @return [
|
48
|
+
# @return [Eth::Key] decrypted key.
|
46
49
|
def perform
|
47
50
|
derive_key password
|
48
51
|
check_macs
|
data/lib/eth/key/encrypter.rb
CHANGED
@@ -12,45 +12,47 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# Provides the
|
15
|
+
# Provides the {Eth} module.
|
16
16
|
module Eth
|
17
17
|
|
18
|
-
# The Eth::Key::Encrypter class to handle PBKDF2-SHA-256 encryption.
|
18
|
+
# The {Eth::Key::Encrypter} class to handle PBKDF2-SHA-256 encryption.
|
19
19
|
class Key::Encrypter
|
20
20
|
|
21
21
|
# Provides a specific encrypter error if decryption fails.
|
22
22
|
class EncrypterError < StandardError; end
|
23
23
|
|
24
|
-
# Class method
|
24
|
+
# Class method {Eth::Key::Encrypter.perform} to performa an key-store
|
25
25
|
# encryption.
|
26
26
|
#
|
27
|
-
# @param key [Eth::Key] representing a secret key-pair used for encryption
|
28
|
-
# @param options [Hash] the options to encrypt with
|
29
|
-
# @option options [String] :kdf key derivation function defaults to pbkdf2
|
30
|
-
# @option options [String] :id uuid given to the secret key
|
31
|
-
# @option options [String] :iterations number of iterations for the hash function
|
32
|
-
# @option options [String] :salt passed to PBKDF
|
33
|
-
# @option options [String] :iv 128-bit initialisation vector for the cipher
|
34
|
-
# @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8
|
35
|
-
# @option options [Integer] :block_size for scrypt, defaults to 1
|
36
|
-
# @return [JSON] formatted with encrypted key (cyphertext) and [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256)
|
27
|
+
# @param key [Eth::Key] representing a secret key-pair used for encryption.
|
28
|
+
# @param options [Hash] the options to encrypt with.
|
29
|
+
# @option options [String] :kdf key derivation function defaults to pbkdf2.
|
30
|
+
# @option options [String] :id uuid given to the secret key.
|
31
|
+
# @option options [String] :iterations number of iterations for the hash function.
|
32
|
+
# @option options [String] :salt passed to PBKDF.
|
33
|
+
# @option options [String] :iv 128-bit initialisation vector for the cipher.
|
34
|
+
# @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8.
|
35
|
+
# @option options [Integer] :block_size for scrypt, defaults to 1.
|
36
|
+
# @return [JSON] formatted with encrypted key (cyphertext) and [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256).
|
37
37
|
def self.perform(key, password, options = {})
|
38
38
|
new(key, options).perform(password)
|
39
39
|
end
|
40
40
|
|
41
|
-
# Constructor of the
|
42
|
-
# encryption.
|
41
|
+
# Constructor of the {Eth::Key::Encrypter} class for secret key
|
42
|
+
# encryption. Should not be used; use {Eth::Key::Encrypter.perform}
|
43
|
+
# instead.
|
43
44
|
#
|
44
|
-
# @param key [Eth::Key] representing a secret key-pair used for encryption
|
45
|
-
# @param options [Hash] the options to encrypt with
|
46
|
-
# @option options [String] :kdf key derivation function defaults to pbkdf2
|
47
|
-
# @option options [String] :id uuid given to the secret key
|
48
|
-
# @option options [String] :iterations number of iterations for the hash function
|
49
|
-
# @option options [String] :salt passed to PBKDF
|
50
|
-
# @option options [String] :iv 128-bit initialisation vector for the cipher
|
51
|
-
# @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8
|
52
|
-
# @option options [Integer] :block_size for scrypt, defaults to 1
|
45
|
+
# @param key [Eth::Key] representing a secret key-pair used for encryption.
|
46
|
+
# @param options [Hash] the options to encrypt with.
|
47
|
+
# @option options [String] :kdf key derivation function defaults to pbkdf2.
|
48
|
+
# @option options [String] :id uuid given to the secret key.
|
49
|
+
# @option options [String] :iterations number of iterations for the hash function.
|
50
|
+
# @option options [String] :salt passed to PBKDF.
|
51
|
+
# @option options [String] :iv 128-bit initialisation vector for the cipher.
|
52
|
+
# @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8.
|
53
|
+
# @option options [Integer] :block_size for scrypt, defaults to 1.
|
53
54
|
def initialize(key, options = {})
|
55
|
+
key = Key.new(priv: key) if key.is_a? String
|
54
56
|
@key = key
|
55
57
|
@options = options
|
56
58
|
|
@@ -64,7 +66,7 @@ module Eth
|
|
64
66
|
# Encrypt the key with a given password.
|
65
67
|
#
|
66
68
|
# @param password [String] a secret key used for encryption
|
67
|
-
# @return [String] a
|
69
|
+
# @return [String] a JSON-formatted keystore string.
|
68
70
|
def perform(password)
|
69
71
|
derive_key password
|
70
72
|
encrypt
|
data/lib/eth/key.rb
CHANGED
@@ -18,28 +18,28 @@ require "rbsecp256k1"
|
|
18
18
|
require "scrypt"
|
19
19
|
require "securerandom"
|
20
20
|
|
21
|
-
# Provides the
|
21
|
+
# Provides the {Eth} module.
|
22
22
|
module Eth
|
23
23
|
|
24
|
-
# The
|
24
|
+
# The {Eth::Key} class to handle Secp256k1 private/public key-pairs.
|
25
25
|
class Key
|
26
26
|
|
27
|
-
# The Eth::Key::Decrypter class to handle PBKDF2-SHA-256 decryption.
|
27
|
+
# The {Eth::Key::Decrypter} class to handle PBKDF2-SHA-256 decryption.
|
28
28
|
autoload :Decrypter, "eth/key/decrypter"
|
29
29
|
|
30
|
-
# The Eth::Key::Encrypter class to handle PBKDF2-SHA-256 encryption.
|
30
|
+
# The {Eth::Key::Encrypter} class to handle PBKDF2-SHA-256 encryption.
|
31
31
|
autoload :Encrypter, "eth/key/encrypter"
|
32
32
|
|
33
|
-
# The `Secp256k1::PrivateKey` of the
|
33
|
+
# The `Secp256k1::PrivateKey` of the {Eth::Key} pair.
|
34
34
|
attr_reader :private_key
|
35
35
|
|
36
|
-
# The `Secp256k1::PublicKey` of the
|
36
|
+
# The `Secp256k1::PublicKey` of the {Eth::Key} pair.
|
37
37
|
attr_reader :public_key
|
38
38
|
|
39
|
-
# Constructor of the
|
39
|
+
# Constructor of the {Eth::Key} class. Creates a new random key-pair
|
40
40
|
# if no `priv` key is provided.
|
41
41
|
#
|
42
|
-
# @param priv [String] binary string of private key data
|
42
|
+
# @param priv [String] binary string of private key data.
|
43
43
|
def initialize(priv: nil)
|
44
44
|
|
45
45
|
# Creates a new, randomized libsecp256k1 context.
|
@@ -63,9 +63,10 @@ module Eth
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Signs arbitrary data without validation. Should not be used unless really
|
66
|
-
# desired. See also: personal_sign, sign_typed_data
|
66
|
+
# desired. See also: {Key.personal_sign}, {Key.sign_typed_data}, and
|
67
|
+
# {Signature.recover}.
|
67
68
|
#
|
68
|
-
# @param blob [
|
69
|
+
# @param blob [Object] that arbitrary data to be signed.
|
69
70
|
# @param chain_id [Integer] the chain id the signature should be generated on.
|
70
71
|
# @return [String] a hexa-decimal signature.
|
71
72
|
def sign(blob, chain_id = nil)
|
@@ -81,9 +82,11 @@ module Eth
|
|
81
82
|
Util.bin_to_hex signature.pack "c*"
|
82
83
|
end
|
83
84
|
|
84
|
-
# Prefixes a message with
|
85
|
+
# Prefixes a message with `\x19Ethereum Signed Message:` and signs
|
85
86
|
# it in the common way used by many web3 wallets. Complies with
|
86
|
-
# EIP-191 prefix 0x19 and version byte 0x45 (E).
|
87
|
+
# EIP-191 prefix `0x19` and version byte `0x45` (`E`). See also
|
88
|
+
# {Signature.personal_recover}.
|
89
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-191
|
87
90
|
#
|
88
91
|
# @param message [String] the message string to be prefixed and signed.
|
89
92
|
# @param chain_id [Integer] the chain id the signature should be generated on.
|
@@ -95,8 +98,10 @@ module Eth
|
|
95
98
|
end
|
96
99
|
|
97
100
|
# Prefixes, hashes, and signes a typed data structure in the common
|
98
|
-
# way used by many web3 wallets. Complies with EIP-191 prefix 0x19
|
99
|
-
# and EIP-712 version byte 0x01
|
101
|
+
# way used by many web3 wallets. Complies with EIP-191 prefix `0x19`
|
102
|
+
# and EIP-712 version byte `0x01`. Supports `V3`, `V4`. See also
|
103
|
+
# {Signature.recover_typed_data}.
|
104
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-712
|
100
105
|
#
|
101
106
|
# @param typed_data [Array] all the data in the typed data structure to be signed.
|
102
107
|
# @param chain_id [Integer] the chain id the signature should be generated on.
|
@@ -114,7 +119,7 @@ module Eth
|
|
114
119
|
end
|
115
120
|
|
116
121
|
# Exports the private key bytes in a wrapper function to maintain
|
117
|
-
# backward-compatibility with older versions of
|
122
|
+
# backward-compatibility with older versions of {Eth::Key}.
|
118
123
|
#
|
119
124
|
# @return [String] private key as packed byte-string.
|
120
125
|
def private_bytes
|
@@ -138,7 +143,7 @@ module Eth
|
|
138
143
|
end
|
139
144
|
|
140
145
|
# Exports the uncompressed public key bytes in a wrapper function to
|
141
|
-
# maintain backward-compatibility with older versions of
|
146
|
+
# maintain backward-compatibility with older versions of {Eth::Key}.
|
142
147
|
#
|
143
148
|
# @return [String] uncompressed public key as packed byte-string.
|
144
149
|
def public_bytes
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
|
20
|
+
# Provides an recursive-length prefix (RLP) encoder and decoder.
|
21
|
+
module Rlp
|
22
|
+
|
23
|
+
# Provides an RLP-decoder.
|
24
|
+
module Decoder
|
25
|
+
extend self
|
26
|
+
|
27
|
+
# Decodes an RLP-encoded object.
|
28
|
+
#
|
29
|
+
# @param rlp [String] an RLP-encoded object.
|
30
|
+
# @return [Object] the decoded and maybe deserialized object.
|
31
|
+
# @raise [Eth::Rlp::DecodingError] if the input string does not end after
|
32
|
+
# the root item.
|
33
|
+
def perform(rlp)
|
34
|
+
rlp = Util.hex_to_bin rlp if Util.is_hex? rlp
|
35
|
+
rlp = Util.str_to_bytes rlp
|
36
|
+
begin
|
37
|
+
item, next_start = consume_item rlp, 0
|
38
|
+
rescue Exception => e
|
39
|
+
raise DecodingError, "Cannot decode rlp string: #{e}"
|
40
|
+
end
|
41
|
+
raise DecodingError, "RLP string ends with #{rlp.size - next_start} superfluous bytes" if next_start != rlp.size
|
42
|
+
return item
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Consume an RLP-encoded item from the given start.
|
48
|
+
def consume_item(rlp, start)
|
49
|
+
t, l, s = consume_length_prefix rlp, start
|
50
|
+
consume_payload rlp, s, t, l
|
51
|
+
end
|
52
|
+
|
53
|
+
# Consume an RLP length prefix at the given position.
|
54
|
+
def consume_length_prefix(rlp, start)
|
55
|
+
b0 = rlp[start].ord
|
56
|
+
if b0 < Constant::PRIMITIVE_PREFIX_OFFSET
|
57
|
+
|
58
|
+
# single byte
|
59
|
+
[:str, 1, start]
|
60
|
+
elsif b0 < Constant::PRIMITIVE_PREFIX_OFFSET + Constant::SHORT_LENGTH_LIMIT
|
61
|
+
raise DecodingError, "Encoded as short string although single byte was possible" if (b0 - Constant::PRIMITIVE_PREFIX_OFFSET == 1) && rlp[start + 1].ord < Constant::PRIMITIVE_PREFIX_OFFSET
|
62
|
+
|
63
|
+
# short string
|
64
|
+
[:str, b0 - Constant::PRIMITIVE_PREFIX_OFFSET, start + 1]
|
65
|
+
elsif b0 < Constant::LIST_PREFIX_OFFSET
|
66
|
+
enforce_no_zero_bytes rlp, start
|
67
|
+
|
68
|
+
# long string
|
69
|
+
ll = b0 - Constant::PRIMITIVE_PREFIX_OFFSET - Constant::SHORT_LENGTH_LIMIT + 1
|
70
|
+
l = Util.big_endian_to_int rlp[(start + 1)...(start + 1 + ll)]
|
71
|
+
raise DecodingError, "Long string prefix used for short string" if l < Constant::SHORT_LENGTH_LIMIT
|
72
|
+
[:str, l, start + 1 + ll]
|
73
|
+
elsif b0 < Constant::LIST_PREFIX_OFFSET + Constant::SHORT_LENGTH_LIMIT
|
74
|
+
|
75
|
+
# short list
|
76
|
+
[:list, b0 - Constant::LIST_PREFIX_OFFSET, start + 1]
|
77
|
+
else
|
78
|
+
enforce_no_zero_bytes rlp, start
|
79
|
+
|
80
|
+
# long list
|
81
|
+
ll = b0 - Constant::LIST_PREFIX_OFFSET - Constant::SHORT_LENGTH_LIMIT + 1
|
82
|
+
l = Util.big_endian_to_int rlp[(start + 1)...(start + 1 + ll)]
|
83
|
+
raise DecodingError, "Long list prefix used for short list" if l < Constant::SHORT_LENGTH_LIMIT
|
84
|
+
[:list, l, start + 1 + ll]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Enforce RLP slices to not start with empty bytes.
|
89
|
+
def enforce_no_zero_bytes(rlp, start)
|
90
|
+
raise DecodingError, "Length starts with zero bytes" if rlp.slice(start + 1) == Constant::BYTE_ZERO
|
91
|
+
end
|
92
|
+
|
93
|
+
# Consume an RLP payload at the given position of given type and size.
|
94
|
+
def consume_payload(rlp, start, type, length)
|
95
|
+
case type
|
96
|
+
when :str
|
97
|
+
[rlp[start...(start + length)], start + length]
|
98
|
+
when :list
|
99
|
+
items = []
|
100
|
+
next_item_start = start
|
101
|
+
payload_end = next_item_start + length
|
102
|
+
while next_item_start < payload_end
|
103
|
+
item, next_item_start = consume_item rlp, next_item_start
|
104
|
+
items.push item
|
105
|
+
end
|
106
|
+
raise DecodingError, "List length prefix announced a too small length" if next_item_start > payload_end
|
107
|
+
[items, next_item_start]
|
108
|
+
else
|
109
|
+
raise TypeError, "Type must be either :str or :list"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
|
20
|
+
# Provides an recursive-length prefix (RLP) encoder and decoder.
|
21
|
+
module Rlp
|
22
|
+
|
23
|
+
# Provides an RLP-encoder.
|
24
|
+
module Encoder
|
25
|
+
extend self
|
26
|
+
|
27
|
+
# Encodes a Ruby object in RLP format.
|
28
|
+
#
|
29
|
+
# @param obj [Object] a Ruby object.
|
30
|
+
# @return [String] the RLP encoded item.
|
31
|
+
# @raise [Eth::Rlp::EncodingError] in the rather unlikely case that the item
|
32
|
+
# is too big to encode (will not happen).
|
33
|
+
# @raise [Eth::Rlp::SerializationError] if the serialization fails.
|
34
|
+
def perform(obj)
|
35
|
+
item = Sedes.infer(obj).serialize(obj)
|
36
|
+
result = encode_raw item
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Encodes the raw item.
|
42
|
+
def encode_raw(item)
|
43
|
+
return item if item.instance_of? Rlp::Data
|
44
|
+
return encode_primitive item if Util.is_primitive? item
|
45
|
+
return encode_list item if Util.is_list? item
|
46
|
+
raise EncodingError "Cannot encode object of type #{item.class.name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Encodes a single primitive.
|
50
|
+
def encode_primitive(item)
|
51
|
+
return Util.str_to_bytes item if item.size == 1 && item.ord < Constant::PRIMITIVE_PREFIX_OFFSET
|
52
|
+
payload = Util.str_to_bytes item
|
53
|
+
prefix = length_prefix payload.size, Constant::PRIMITIVE_PREFIX_OFFSET
|
54
|
+
"#{prefix}#{payload}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Encodes a single list.
|
58
|
+
def encode_list(list)
|
59
|
+
payload = list.map { |item| encode_raw item }.join
|
60
|
+
prefix = length_prefix payload.size, Constant::LIST_PREFIX_OFFSET
|
61
|
+
"#{prefix}#{payload}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Determines a length prefix.
|
65
|
+
def length_prefix(length, offset)
|
66
|
+
if length < Constant::SHORT_LENGTH_LIMIT
|
67
|
+
(offset + length).chr
|
68
|
+
elsif length < Constant::LONG_LENGTH_LIMIT
|
69
|
+
length_string = Util.int_to_big_endian length
|
70
|
+
length_len = (offset + Constant::SHORT_LENGTH_LIMIT - 1 + length_string.size).chr
|
71
|
+
"#{length_len}#{length_string}"
|
72
|
+
else
|
73
|
+
raise EncodingError, "Length greater than 256**8: #{length}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|