eth 0.5.0 → 0.5.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/.github/workflows/codeql.yml +4 -0
- data/.github/workflows/spec.yml +14 -3
- data/.yardopts +1 -0
- data/AUTHORS.txt +5 -0
- data/CHANGELOG.md +63 -13
- data/README.md +57 -2
- data/bin/console +2 -1
- data/bin/setup +3 -4
- data/eth.gemspec +5 -7
- data/lib/eth/abi/type.rb +8 -7
- data/lib/eth/abi.rb +17 -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 +47 -0
- data/lib/eth/client.rb +232 -0
- data/lib/eth/constant.rb +71 -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 +109 -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/tx/eip1559.rb +21 -14
- data/lib/eth/tx/eip2930.rb +22 -15
- data/lib/eth/tx/legacy.rb +13 -10
- data/lib/eth/tx.rb +9 -10
- 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 +8 -2
- metadata +22 -23
- data/lib/eth/abi/constant.rb +0 -63
@@ -0,0 +1,84 @@
|
|
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 serializable and deserializable types (SeDes).
|
24
|
+
module Sedes
|
25
|
+
|
26
|
+
# A sedes type for lists of fixed length.
|
27
|
+
class List < Array
|
28
|
+
|
29
|
+
# Create a serializable list of fixed size.
|
30
|
+
#
|
31
|
+
# @param elements [Array] an array indicating the structure of the list.
|
32
|
+
# @param strict [Boolean] an option to enforce the given structure.
|
33
|
+
def initialize(elements: [], strict: true)
|
34
|
+
super()
|
35
|
+
@strict = strict
|
36
|
+
elements.each do |e|
|
37
|
+
if Sedes.is_sedes?(e)
|
38
|
+
push e
|
39
|
+
elsif Util.is_list?(e)
|
40
|
+
push List.new(elements: e)
|
41
|
+
else
|
42
|
+
raise TypeError, "Instances of List must only contain sedes objects or nested sequences thereof."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Serialize an array.
|
48
|
+
#
|
49
|
+
# @param obj [Array] the array to be serialized.
|
50
|
+
# @return [Array] a serialized list.
|
51
|
+
# @raise [SerializationError] if provided array is not a sequence.
|
52
|
+
# @raise [SerializationError] if provided array is of wrong length.
|
53
|
+
def serialize(obj)
|
54
|
+
raise SerializationError, "Can only serialize sequences" unless Util.is_list?(obj)
|
55
|
+
raise SerializationError, "List has wrong length" if (@strict && self.size != obj.size) || self.size < obj.size
|
56
|
+
result = []
|
57
|
+
obj.zip(self).each_with_index do |(element, sedes), i|
|
58
|
+
result.push sedes.serialize(element)
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
# Deserializes a list.
|
64
|
+
#
|
65
|
+
# @param serial [Array] the serialized list.
|
66
|
+
# @return [Array] a deserialized list.
|
67
|
+
# @raise [DeserializationError] if provided serial is not a sequence.
|
68
|
+
# @raise [DeserializationError] if provided serial is of wrong length.
|
69
|
+
def deserialize(serial)
|
70
|
+
raise DeserializationError, "Can only deserialize sequences" unless Util.is_list?(serial)
|
71
|
+
raise DeserializationError, "List has wrong length" if @strict && serial.size != self.size
|
72
|
+
result = []
|
73
|
+
len = [serial.size, self.size].min
|
74
|
+
len.times do |i|
|
75
|
+
sedes = self[i]
|
76
|
+
element = serial[i]
|
77
|
+
result.push sedes.deserialize(element)
|
78
|
+
end
|
79
|
+
result.freeze
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,74 @@
|
|
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
|
+
require "eth/rlp/sedes/big_endian_int"
|
18
|
+
require "eth/rlp/sedes/binary"
|
19
|
+
require "eth/rlp/sedes/list"
|
20
|
+
|
21
|
+
# Provides the {Eth} module.
|
22
|
+
module Eth
|
23
|
+
|
24
|
+
# Provides an recursive-length prefix (RLP) encoder and decoder.
|
25
|
+
module Rlp
|
26
|
+
|
27
|
+
# Provides serializable and deserializable types (SeDes).
|
28
|
+
module Sedes
|
29
|
+
|
30
|
+
# Provides a singleton {Eth::Rlp::Sedes} class to infer objects and types.
|
31
|
+
class << self
|
32
|
+
|
33
|
+
# Tries to find a sedes objects suitable for a given Ruby object.
|
34
|
+
#
|
35
|
+
# The sedes objects considered are `obj`'s class, {big_endian_int} and
|
36
|
+
# {binary}. If `obj` is a list, an {Eth::Rlp::Sedes::List} will be
|
37
|
+
# constructed recursively.
|
38
|
+
#
|
39
|
+
# @param obj [Object] the Ruby object for which to find a sedes object.
|
40
|
+
# @raise [TypeError] if no appropriate sedes could be found.
|
41
|
+
def infer(obj)
|
42
|
+
return obj.class if is_sedes? obj.class
|
43
|
+
return big_endian_int if obj.is_a?(Integer) && obj >= 0
|
44
|
+
return binary if Binary.valid_type? obj
|
45
|
+
return List.new(elements: obj.map { |item| infer item }) if Util.is_list? obj
|
46
|
+
raise TypeError, "Did not find sedes handling type #{obj.class.name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Determines if an object is a sedes object.
|
50
|
+
#
|
51
|
+
# @param obj [Object] the object to check.
|
52
|
+
# @return [Boolean] true if it's serializable and deserializable.
|
53
|
+
def is_sedes?(obj)
|
54
|
+
obj.respond_to?(:serialize) && obj.respond_to?(:deserialize)
|
55
|
+
end
|
56
|
+
|
57
|
+
# A utility to use a big-endian, unsigned integer sedes type with
|
58
|
+
# unspecified length.
|
59
|
+
#
|
60
|
+
# @return [Eth::Rlp::Sedes::BigEndianInt] a big-endian, unsigned integer sedes.
|
61
|
+
def big_endian_int
|
62
|
+
@big_endian_int ||= BigEndianInt.new
|
63
|
+
end
|
64
|
+
|
65
|
+
# A utility to use a binary sedes type.
|
66
|
+
#
|
67
|
+
# @return [Eth::Rlp::Sedes::Binary] a binary sedes.
|
68
|
+
def binary
|
69
|
+
@binary ||= Binary.new
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/eth/rlp.rb
ADDED
@@ -0,0 +1,63 @@
|
|
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
|
+
require "eth/rlp/decoder"
|
18
|
+
require "eth/rlp/encoder"
|
19
|
+
require "eth/rlp/sedes"
|
20
|
+
require "eth/util"
|
21
|
+
|
22
|
+
# Provides the {Eth} module.
|
23
|
+
module Eth
|
24
|
+
|
25
|
+
# Provides an recursive-length prefix (RLP) encoder and decoder.
|
26
|
+
module Rlp
|
27
|
+
extend self
|
28
|
+
|
29
|
+
# The Rlp module exposes a variety of exceptions grouped as {RlpException}.
|
30
|
+
class RlpException < StandardError; end
|
31
|
+
|
32
|
+
# An error-type to point out RLP-encoding errors.
|
33
|
+
class EncodingError < RlpException; end
|
34
|
+
|
35
|
+
# An error-type to point out RLP-decoding errors.
|
36
|
+
class DecodingError < RlpException; end
|
37
|
+
|
38
|
+
# An error-type to point out RLP-type serialization errors.
|
39
|
+
class SerializationError < RlpException; end
|
40
|
+
|
41
|
+
# An error-type to point out RLP-type serialization errors.
|
42
|
+
class DeserializationError < RlpException; end
|
43
|
+
|
44
|
+
# A wrapper to represent already RLP-encoded data.
|
45
|
+
class Data < String; end
|
46
|
+
|
47
|
+
# Performes an {Eth::Rlp::Encoder} on any ruby object.
|
48
|
+
#
|
49
|
+
# @param obj [Object] any ruby object.
|
50
|
+
# @return [String] a packed, RLP-encoded item.
|
51
|
+
def encode(obj)
|
52
|
+
Rlp::Encoder.perform obj
|
53
|
+
end
|
54
|
+
|
55
|
+
# Performes an {Eth::Rlp::Decoder} on any RLP-encoded item.
|
56
|
+
#
|
57
|
+
# @param rlp [String] a packed, RLP-encoded item.
|
58
|
+
# @return [Object] a decoded ruby object.
|
59
|
+
def decode(rlp)
|
60
|
+
Rlp::Decoder.perform rlp
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/eth/signature.rb
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
require "rbsecp256k1"
|
16
16
|
|
17
|
-
# Provides the
|
17
|
+
# Provides the {Eth} module.
|
18
18
|
module Eth
|
19
19
|
|
20
20
|
# Defines handy tools for verifying and recovering signatures.
|
@@ -30,21 +30,22 @@ module Eth
|
|
30
30
|
# EIP-712 version byte 0x01
|
31
31
|
EIP712_VERSION_BYTE = "\x01".freeze
|
32
32
|
|
33
|
-
# Prefix message as per EIP-191 with 0x19 to ensure the data is not
|
33
|
+
# Prefix message as per EIP-191 with `0x19` to ensure the data is not
|
34
34
|
# valid RLP and thus not mistaken for a transaction.
|
35
|
-
# EIP-191 Version byte: 0x45 (E)
|
36
|
-
#
|
35
|
+
# EIP-191 Version byte: `0x45` (`E`)
|
36
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-191
|
37
37
|
#
|
38
38
|
# @param message [String] the message string to be prefixed.
|
39
|
-
# @return [String] an EIP-191 prefixed string
|
39
|
+
# @return [String] an EIP-191 prefixed string.
|
40
40
|
def prefix_message(message)
|
41
41
|
"#{EIP191_PREFIX_BYTE}Ethereum Signed Message:\n#{message.size}#{message}"
|
42
42
|
end
|
43
43
|
|
44
|
-
# Dissects a signature blob of 65 bytes into its r
|
44
|
+
# Dissects a signature blob of 65+ bytes into its `r`, `s`, and `v`
|
45
|
+
# values.
|
45
46
|
#
|
46
|
-
# @param signature [String] a Secp256k1 signature.
|
47
|
-
# @return [String, String, String] the r
|
47
|
+
# @param signature [String] a concatenated Secp256k1 signature string.
|
48
|
+
# @return [String, String, String] the `r`, `s`, and `v` values.
|
48
49
|
# @raise [SignatureError] if signature is of unknown size.
|
49
50
|
def dissect(signature)
|
50
51
|
signature = Util.bin_to_hex signature unless Util.is_hex? signature
|
@@ -79,6 +80,7 @@ module Eth
|
|
79
80
|
|
80
81
|
# Recovers a public key from a prefixed, personal message and
|
81
82
|
# a signature on a given chain. (EIP-191)
|
83
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-191
|
82
84
|
#
|
83
85
|
# @param message [String] the message string.
|
84
86
|
# @param signature [String] the hex string containing the signature.
|
@@ -92,6 +94,7 @@ module Eth
|
|
92
94
|
|
93
95
|
# Recovers a public key from a typed data structure and a signature
|
94
96
|
# on a given chain. (EIP-712)
|
97
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-712
|
95
98
|
#
|
96
99
|
# @param typed_data [Array] all the data in the typed data structure to be recovered.
|
97
100
|
# @param signature [String] the hex string containing the signature.
|
data/lib/eth/tx/eip1559.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
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
|
# Provides the `Tx` module supporting various transaction types.
|
@@ -20,9 +20,11 @@ module Eth
|
|
20
20
|
|
21
21
|
# Provides support for EIP-1559 transactions utilizing EIP-2718
|
22
22
|
# types and envelopes.
|
23
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-1559
|
23
24
|
class Eip1559
|
24
25
|
|
25
26
|
# The EIP-155 Chain ID.
|
27
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-155
|
26
28
|
attr_reader :chain_id
|
27
29
|
|
28
30
|
# The transaction nonce provided by the signer.
|
@@ -47,6 +49,7 @@ module Eth
|
|
47
49
|
attr_reader :payload
|
48
50
|
|
49
51
|
# An optional EIP-2930 access list.
|
52
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-2930
|
50
53
|
attr_reader :access_list
|
51
54
|
|
52
55
|
# The signature's y-parity byte (not v).
|
@@ -66,8 +69,10 @@ module Eth
|
|
66
69
|
|
67
70
|
# Create a type-2 (EIP-1559) transaction payload object that
|
68
71
|
# can be prepared for envelope, signature and broadcast.
|
72
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-1559
|
69
73
|
#
|
70
74
|
# @param params [Hash] all necessary transaction fields.
|
75
|
+
# @option params [Integer] :chain_id the chain ID.
|
71
76
|
# @option params [Integer] :nonce the signer nonce.
|
72
77
|
# @option params [Integer] :priority_fee the max priority fee per gas.
|
73
78
|
# @option params [Integer] :max_gas_fee the max transaction fee per gas.
|
@@ -77,6 +82,7 @@ module Eth
|
|
77
82
|
# @option params [Integer] :value the transaction value.
|
78
83
|
# @option params [String] :data the transaction data payload.
|
79
84
|
# @option params [Array] :access_list an optional access list.
|
85
|
+
# @raise [ParameterError] if gas limit is too low.
|
80
86
|
def initialize(params)
|
81
87
|
fields = { recovery_id: nil, r: 0, s: 0 }.merge params
|
82
88
|
|
@@ -121,7 +127,7 @@ module Eth
|
|
121
127
|
# Overloads the constructor for decoding raw transactions and creating unsigned copies.
|
122
128
|
konstructor :decode, :unsigned_copy
|
123
129
|
|
124
|
-
# Decodes a raw transaction hex into an Eth::Tx::Eip1559
|
130
|
+
# Decodes a raw transaction hex into an {Eth::Tx::Eip1559}
|
125
131
|
# transaction object.
|
126
132
|
#
|
127
133
|
# @param hex [String] the raw transaction hex-string.
|
@@ -135,7 +141,7 @@ module Eth
|
|
135
141
|
raise TransactionTypeError, "Invalid transaction type #{type}!" if type.to_i(16) != TYPE_1559
|
136
142
|
|
137
143
|
bin = Util.hex_to_bin hex[2..]
|
138
|
-
tx =
|
144
|
+
tx = Rlp.decode bin
|
139
145
|
|
140
146
|
# decoded transactions always have 9 + 3 fields, even if they are empty or zero
|
141
147
|
raise ParameterError, "Transaction missing fields!" if tx.size < 9
|
@@ -221,8 +227,8 @@ module Eth
|
|
221
227
|
#
|
222
228
|
# @param key [Eth::Key] the key-pair to use for signing.
|
223
229
|
# @return [String] a transaction hash.
|
224
|
-
# @raise [SignatureError] if transaction is already signed.
|
225
|
-
# @raise [SignatureError] if sender address does not match signing key.
|
230
|
+
# @raise [Signature::SignatureError] if transaction is already signed.
|
231
|
+
# @raise [Signature::SignatureError] if sender address does not match signing key.
|
226
232
|
def sign(key)
|
227
233
|
if Tx.is_signed? self
|
228
234
|
raise Signature::SignatureError, "Transaction is already signed!"
|
@@ -249,7 +255,7 @@ module Eth
|
|
249
255
|
# with an EIP-1559 type prefix.
|
250
256
|
#
|
251
257
|
# @return [String] a raw, RLP-encoded EIP-1559 type transaction object.
|
252
|
-
# @raise [SignatureError] if the transaction is not yet signed.
|
258
|
+
# @raise [Signature::SignatureError] if the transaction is not yet signed.
|
253
259
|
def encoded
|
254
260
|
unless Tx.is_signed? self
|
255
261
|
raise Signature::SignatureError, "Transaction is not signed!"
|
@@ -262,12 +268,12 @@ module Eth
|
|
262
268
|
tx_data.push Util.serialize_int_to_big_endian @gas_limit
|
263
269
|
tx_data.push Util.hex_to_bin @destination
|
264
270
|
tx_data.push Util.serialize_int_to_big_endian @amount
|
265
|
-
tx_data.push @payload
|
266
|
-
tx_data.push @access_list
|
271
|
+
tx_data.push Rlp::Sedes.binary.serialize @payload
|
272
|
+
tx_data.push Rlp::Sedes.infer(@access_list).serialize @access_list
|
267
273
|
tx_data.push Util.serialize_int_to_big_endian @signature_y_parity
|
268
|
-
tx_data.push Util.
|
269
|
-
tx_data.push Util.
|
270
|
-
tx_encoded =
|
274
|
+
tx_data.push Util.serialize_int_to_big_endian @signature_r
|
275
|
+
tx_data.push Util.serialize_int_to_big_endian @signature_s
|
276
|
+
tx_encoded = Rlp.encode tx_data
|
271
277
|
|
272
278
|
# create an EIP-2718 envelope with EIP-1559 type payload
|
273
279
|
tx_type = Util.serialize_int_to_big_endian @type
|
@@ -301,9 +307,9 @@ module Eth
|
|
301
307
|
tx_data.push Util.serialize_int_to_big_endian @gas_limit
|
302
308
|
tx_data.push Util.hex_to_bin @destination
|
303
309
|
tx_data.push Util.serialize_int_to_big_endian @amount
|
304
|
-
tx_data.push @payload
|
305
|
-
tx_data.push @access_list
|
306
|
-
tx_encoded =
|
310
|
+
tx_data.push Rlp::Sedes.binary.serialize @payload
|
311
|
+
tx_data.push Rlp::Sedes.infer(@access_list).serialize @access_list
|
312
|
+
tx_encoded = Rlp.encode tx_data
|
307
313
|
|
308
314
|
# create an EIP-2718 envelope with EIP-1559 type payload (unsigned)
|
309
315
|
tx_type = Util.serialize_int_to_big_endian @type
|
@@ -319,6 +325,7 @@ module Eth
|
|
319
325
|
|
320
326
|
private
|
321
327
|
|
328
|
+
# Force-sets an existing signature of a decoded transaction.
|
322
329
|
def _set_signature(recovery_id, r, s)
|
323
330
|
@signature_y_parity = recovery_id
|
324
331
|
@signature_r = r
|
data/lib/eth/tx/eip2930.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
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
|
# Provides the `Tx` module supporting various transaction types.
|
@@ -20,9 +20,11 @@ module Eth
|
|
20
20
|
|
21
21
|
# Provides legacy support for transactions on blockchains that do not
|
22
22
|
# implement EIP-1559 but still want to utilize EIP-2718 envelopes.
|
23
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-2930
|
23
24
|
class Eip2930
|
24
25
|
|
25
26
|
# The EIP-155 Chain ID.
|
27
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-155
|
26
28
|
attr_reader :chain_id
|
27
29
|
|
28
30
|
# The transaction nonce provided by the signer.
|
@@ -44,9 +46,10 @@ module Eth
|
|
44
46
|
attr_reader :payload
|
45
47
|
|
46
48
|
# An optional EIP-2930 access list.
|
49
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-2930
|
47
50
|
attr_reader :access_list
|
48
51
|
|
49
|
-
# The signature's y
|
52
|
+
# The signature's `y`-parity byte (not `v`).
|
50
53
|
attr_reader :signature_y_parity
|
51
54
|
|
52
55
|
# The signature `r` value.
|
@@ -64,9 +67,11 @@ module Eth
|
|
64
67
|
# Create a legacy type-1 (EIP-2930) transaction payload object that
|
65
68
|
# can be prepared for envelope, signature and broadcast. Should not
|
66
69
|
# be used unless there is no EIP-1559 support.
|
70
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-2930
|
67
71
|
#
|
68
72
|
#
|
69
73
|
# @param params [Hash] all necessary transaction fields.
|
74
|
+
# @option params [Integer] :chain_id the chain ID.
|
70
75
|
# @option params [Integer] :nonce the signer nonce.
|
71
76
|
# @option params [Integer] :gas_price the gas price.
|
72
77
|
# @option params [Integer] :gas_limit the gas limit.
|
@@ -75,6 +80,7 @@ module Eth
|
|
75
80
|
# @option params [Integer] :value the transaction value.
|
76
81
|
# @option params [String] :data the transaction data payload.
|
77
82
|
# @option params [Array] :access_list an optional access list.
|
83
|
+
# @raise [ParameterError] if gas limit is too low.
|
78
84
|
def initialize(params)
|
79
85
|
fields = { recovery_id: nil, r: 0, s: 0 }.merge params
|
80
86
|
|
@@ -118,7 +124,7 @@ module Eth
|
|
118
124
|
# Overloads the constructor for decoding raw transactions and creating unsigned copies.
|
119
125
|
konstructor :decode, :unsigned_copy
|
120
126
|
|
121
|
-
# Decodes a raw transaction hex into an Eth::Tx::Eip2930
|
127
|
+
# Decodes a raw transaction hex into an {Eth::Tx::Eip2930}
|
122
128
|
# transaction object.
|
123
129
|
#
|
124
130
|
# @param hex [String] the raw transaction hex-string.
|
@@ -132,7 +138,7 @@ module Eth
|
|
132
138
|
raise TransactionTypeError, "Invalid transaction type #{type}!" if type.to_i(16) != TYPE_2930
|
133
139
|
|
134
140
|
bin = Util.hex_to_bin hex[2..]
|
135
|
-
tx =
|
141
|
+
tx = Rlp.decode bin
|
136
142
|
|
137
143
|
# decoded transactions always have 8 + 3 fields, even if they are empty or zero
|
138
144
|
raise ParameterError, "Transaction missing fields!" if tx.size < 8
|
@@ -215,8 +221,8 @@ module Eth
|
|
215
221
|
#
|
216
222
|
# @param key [Eth::Key] the key-pair to use for signing.
|
217
223
|
# @return [String] a transaction hash.
|
218
|
-
# @raise [SignatureError] if transaction is already signed.
|
219
|
-
# @raise [SignatureError] if sender address does not match signing key.
|
224
|
+
# @raise [Signature::SignatureError] if transaction is already signed.
|
225
|
+
# @raise [Signature::SignatureError] if sender address does not match signing key.
|
220
226
|
def sign(key)
|
221
227
|
if Tx.is_signed? self
|
222
228
|
raise Signature::SignatureError, "Transaction is already signed!"
|
@@ -243,7 +249,7 @@ module Eth
|
|
243
249
|
# with an EIP-2930 type prefix.
|
244
250
|
#
|
245
251
|
# @return [String] a raw, RLP-encoded EIP-2930 type transaction object.
|
246
|
-
# @raise [SignatureError] if the transaction is not yet signed.
|
252
|
+
# @raise [Signature::SignatureError] if the transaction is not yet signed.
|
247
253
|
def encoded
|
248
254
|
unless Tx.is_signed? self
|
249
255
|
raise Signature::SignatureError, "Transaction is not signed!"
|
@@ -255,12 +261,12 @@ module Eth
|
|
255
261
|
tx_data.push Util.serialize_int_to_big_endian @gas_limit
|
256
262
|
tx_data.push Util.hex_to_bin @destination
|
257
263
|
tx_data.push Util.serialize_int_to_big_endian @amount
|
258
|
-
tx_data.push @payload
|
259
|
-
tx_data.push @access_list
|
264
|
+
tx_data.push Rlp::Sedes.binary.serialize @payload
|
265
|
+
tx_data.push Rlp::Sedes.infer(@access_list).serialize @access_list
|
260
266
|
tx_data.push Util.serialize_int_to_big_endian @signature_y_parity
|
261
|
-
tx_data.push Util.
|
262
|
-
tx_data.push Util.
|
263
|
-
tx_encoded =
|
267
|
+
tx_data.push Util.serialize_int_to_big_endian @signature_r
|
268
|
+
tx_data.push Util.serialize_int_to_big_endian @signature_s
|
269
|
+
tx_encoded = Rlp.encode tx_data
|
264
270
|
|
265
271
|
# create an EIP-2718 envelope with EIP-2930 type payload
|
266
272
|
tx_type = Util.serialize_int_to_big_endian @type
|
@@ -293,9 +299,9 @@ module Eth
|
|
293
299
|
tx_data.push Util.serialize_int_to_big_endian @gas_limit
|
294
300
|
tx_data.push Util.hex_to_bin @destination
|
295
301
|
tx_data.push Util.serialize_int_to_big_endian @amount
|
296
|
-
tx_data.push @payload
|
297
|
-
tx_data.push @access_list
|
298
|
-
tx_encoded =
|
302
|
+
tx_data.push Rlp::Sedes.binary.serialize @payload
|
303
|
+
tx_data.push Rlp::Sedes.infer(@access_list).serialize @access_list
|
304
|
+
tx_encoded = Rlp.encode tx_data
|
299
305
|
|
300
306
|
# create an EIP-2718 envelope with EIP-2930 type payload (unsigned)
|
301
307
|
tx_type = Util.serialize_int_to_big_endian @type
|
@@ -311,6 +317,7 @@ module Eth
|
|
311
317
|
|
312
318
|
private
|
313
319
|
|
320
|
+
# Force-sets an existing signature of a decoded transaction.
|
314
321
|
def _set_signature(recovery_id, r, s)
|
315
322
|
@signature_y_parity = recovery_id
|
316
323
|
@signature_r = r
|
data/lib/eth/tx/legacy.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
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
|
# Provides the `Tx` module supporting various transaction types.
|
@@ -50,6 +50,7 @@ module Eth
|
|
50
50
|
attr_reader :signature_s
|
51
51
|
|
52
52
|
# The EIP-155 chain ID field.
|
53
|
+
# Ref: https://eips.ethereum.org/EIPS/eip-155
|
53
54
|
attr_reader :chain_id
|
54
55
|
|
55
56
|
# The sender address.
|
@@ -71,6 +72,7 @@ module Eth
|
|
71
72
|
# @option params [Integer] :value the transaction value.
|
72
73
|
# @option params [String] :data the transaction data payload.
|
73
74
|
# @param chain_id [Integer] the EIP-155 Chain ID.
|
75
|
+
# @raise [ParameterError] if gas limit is too low.
|
74
76
|
def initialize(params, chain_id = Chain::ETHEREUM)
|
75
77
|
fields = { v: chain_id, r: 0, s: 0 }.merge params
|
76
78
|
|
@@ -111,7 +113,7 @@ module Eth
|
|
111
113
|
# overloads the constructor for decoding raw transactions and creating unsigned copies
|
112
114
|
konstructor :decode, :unsigned_copy
|
113
115
|
|
114
|
-
# Decodes a raw transaction hex into an Eth::Tx::Legacy
|
116
|
+
# Decodes a raw transaction hex into an {Eth::Tx::Legacy}
|
115
117
|
# transaction object.
|
116
118
|
#
|
117
119
|
# @param hex [String] the raw transaction hex-string.
|
@@ -119,7 +121,7 @@ module Eth
|
|
119
121
|
# @raise [ParameterError] if transaction misses fields.
|
120
122
|
def decode(hex)
|
121
123
|
bin = Util.hex_to_bin hex
|
122
|
-
tx =
|
124
|
+
tx = Rlp.decode bin
|
123
125
|
|
124
126
|
# decoded transactions always have 9 fields, even if they are empty or zero
|
125
127
|
raise ParameterError, "Transaction missing fields!" if tx.size < 9
|
@@ -199,8 +201,8 @@ module Eth
|
|
199
201
|
#
|
200
202
|
# @param key [Eth::Key] the key-pair to use for signing.
|
201
203
|
# @return [String] a transaction hash.
|
202
|
-
# @raise [SignatureError] if transaction is already signed.
|
203
|
-
# @raise [SignatureError] if sender address does not match signing key.
|
204
|
+
# @raise [Signature::SignatureError] if transaction is already signed.
|
205
|
+
# @raise [Signature::SignatureError] if sender address does not match signing key.
|
204
206
|
def sign(key)
|
205
207
|
if Tx.is_signed? self
|
206
208
|
raise Signature::SignatureError, "Transaction is already signed!"
|
@@ -225,7 +227,7 @@ module Eth
|
|
225
227
|
# Encodes a raw transaction object.
|
226
228
|
#
|
227
229
|
# @return [String] a raw, RLP-encoded legacy transaction.
|
228
|
-
# @raise [SignatureError] if the transaction is not yet signed.
|
230
|
+
# @raise [Signature::SignatureError] if the transaction is not yet signed.
|
229
231
|
def encoded
|
230
232
|
unless Tx.is_signed? self
|
231
233
|
raise Signature::SignatureError, "Transaction is not signed!"
|
@@ -236,11 +238,11 @@ module Eth
|
|
236
238
|
tx_data.push Util.serialize_int_to_big_endian @gas_limit
|
237
239
|
tx_data.push Util.hex_to_bin @destination
|
238
240
|
tx_data.push Util.serialize_int_to_big_endian @amount
|
239
|
-
tx_data.push @payload
|
241
|
+
tx_data.push Rlp::Sedes.binary.serialize @payload
|
240
242
|
tx_data.push Util.serialize_int_to_big_endian @signature_v
|
241
243
|
tx_data.push Util.serialize_int_to_big_endian @signature_r
|
242
244
|
tx_data.push Util.serialize_int_to_big_endian @signature_s
|
243
|
-
|
245
|
+
Rlp.encode tx_data
|
244
246
|
end
|
245
247
|
|
246
248
|
# Gets the encoded, raw transaction hex.
|
@@ -267,11 +269,11 @@ module Eth
|
|
267
269
|
tx_data.push Util.serialize_int_to_big_endian @gas_limit
|
268
270
|
tx_data.push Util.hex_to_bin @destination
|
269
271
|
tx_data.push Util.serialize_int_to_big_endian @amount
|
270
|
-
tx_data.push @payload
|
272
|
+
tx_data.push Rlp::Sedes.binary.serialize @payload
|
271
273
|
tx_data.push Util.serialize_int_to_big_endian @chain_id
|
272
274
|
tx_data.push Util.serialize_int_to_big_endian 0
|
273
275
|
tx_data.push Util.serialize_int_to_big_endian 0
|
274
|
-
|
276
|
+
Rlp.encode tx_data
|
275
277
|
end
|
276
278
|
|
277
279
|
# Gets the sign-hash required to sign a raw transaction.
|
@@ -283,6 +285,7 @@ module Eth
|
|
283
285
|
|
284
286
|
private
|
285
287
|
|
288
|
+
# Force-sets an existing signature of a decoded transaction.
|
286
289
|
def _set_signature(v, r, s)
|
287
290
|
@signature_v = v
|
288
291
|
@signature_r = r
|