ethlite 0.4.1 → 1.0.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.
- checksums.yaml +4 -4
- data/Manifest.txt +0 -3
- data/README.md +5 -6
- data/Rakefile +1 -1
- data/lib/ethlite/contract.rb +26 -40
- data/lib/ethlite/utils.rb +17 -206
- data/lib/ethlite/version.rb +3 -3
- data/lib/ethlite.rb +9 -14
- data/lib/jsonrpc/jsonrpc.rb +18 -4
- metadata +4 -7
- data/lib/ethlite/abi/codec.rb +0 -436
- data/lib/ethlite/abi/type.rb +0 -200
- data/lib/ethlite/constant.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 783bf5485da84a9532d36a9285b08b7ebc6e8266b4c431ce623d4720ffefbaf4
|
4
|
+
data.tar.gz: 71e360e28ee30b99ee44accb575c56a6c6b08eb349ec257576dfa4cbb79982f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77e14ee4da005f731958fc5c889d71c59aff89c9a565dec0ea58c0bd56562ba4d8cdf696182a58051a0201b95254ce28a2e4281459976dc0e8c650beeb53b0d7
|
7
|
+
data.tar.gz: b3d9aadf29db07b1afdd53c780a59947d94d0667b070ba0edf45097c3c65f76a492289a2b9f21a20f8a0dc62ea3a0b630d686cdd15f795e18355f32956e78ad9
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -64,7 +64,7 @@ def eth_call( rpc,
|
|
64
64
|
## binary encode method sig(nature)
|
65
65
|
signature = "#{name}(#{inputs.join(',')})"
|
66
66
|
signature_hash = Ethlite::Utils.encode_hex(
|
67
|
-
Ethlite::Utils.keccak256(signature)
|
67
|
+
Ethlite::Utils.keccak256(signature)[0,4])
|
68
68
|
|
69
69
|
pp signature
|
70
70
|
# => "tokenURI(uint256)"
|
@@ -73,7 +73,7 @@ def eth_call( rpc,
|
|
73
73
|
|
74
74
|
## binary encode method arg(ument)s
|
75
75
|
args_encoded = Ethlite::Utils.encode_hex(
|
76
|
-
|
76
|
+
ABI.encode( inputs, args) )
|
77
77
|
|
78
78
|
data = '0x' + signature_hash + args_encoded
|
79
79
|
|
@@ -90,10 +90,9 @@ def eth_call( rpc,
|
|
90
90
|
puts "response:"
|
91
91
|
pp response
|
92
92
|
|
93
|
-
## decode binary result
|
94
|
-
|
95
|
-
|
96
|
-
result = Ethlite::Abi.decode_abi( outputs, string_data )
|
93
|
+
## decode binary result (returned as a hex string starting with 0x)
|
94
|
+
bin = Ethlite::Utils.decode_hex( response )
|
95
|
+
result = ABI.decode( outputs, bin )
|
97
96
|
result.length == 1 ? result[0] : result
|
98
97
|
end
|
99
98
|
```
|
data/Rakefile
CHANGED
data/lib/ethlite/contract.rb
CHANGED
@@ -1,31 +1,6 @@
|
|
1
1
|
module Ethlite
|
2
2
|
class ContractMethod
|
3
3
|
|
4
|
-
def self.parse_abi( abi )
|
5
|
-
## convenience helper - auto-convert to json if string passed in
|
6
|
-
abi = JSON.parse( abi ) if abi.is_a?( String )
|
7
|
-
|
8
|
-
name = abi['name']
|
9
|
-
constant = !!abi['constant'] || abi['stateMutability']=='view'
|
10
|
-
input_types = abi['inputs'] ? abi['inputs'].map{|a| _parse_component_type( a ) } : []
|
11
|
-
output_types = abi['outputs'] ? abi['outputs'].map{|a| _parse_component_type( a ) } : []
|
12
|
-
|
13
|
-
new( name, inputs: input_types,
|
14
|
-
outputs: output_types,
|
15
|
-
constant: constant )
|
16
|
-
end
|
17
|
-
|
18
|
-
def self._parse_component_type( argument )
|
19
|
-
if argument['type'] =~ /^tuple((\[[0-9]*\])*)/
|
20
|
-
argument['components'] ? "(#{argument['components'].collect{ |c| _parse_component_type( c ) }.join(',')})#{$1}"
|
21
|
-
: "()#{$1}"
|
22
|
-
else
|
23
|
-
argument['type']
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
4
|
|
30
5
|
attr_reader :signature,
|
31
6
|
:name,
|
@@ -34,21 +9,25 @@
|
|
34
9
|
:output_types,
|
35
10
|
:constant
|
36
11
|
|
37
|
-
def initialize( name, inputs
|
12
|
+
def initialize( name, inputs: [],
|
38
13
|
outputs: [],
|
39
14
|
constant: true )
|
40
15
|
@name = name
|
41
16
|
@constant = constant
|
42
|
-
|
43
|
-
|
44
|
-
@
|
45
|
-
@
|
17
|
+
|
18
|
+
## parse inputs & outputs into types
|
19
|
+
@input_types = inputs.map { |str| ABI::Type.parse( str ) }
|
20
|
+
@output_types = outputs.map { |str| ABI::Type.parse( str ) }
|
21
|
+
|
22
|
+
types = @input_types.map {|type| type.format }.join(',')
|
23
|
+
@signature = "#{@name}(#{types})"
|
24
|
+
@signature_hash = Utils.encode_hex( Utils.keccak256( @signature)[0,4] )
|
46
25
|
end
|
47
26
|
|
48
27
|
|
49
28
|
def do_call( rpc, contract_address, args )
|
50
29
|
data = '0x' + @signature_hash + Utils.encode_hex(
|
51
|
-
|
30
|
+
ABI.encode(@input_types, args) )
|
52
31
|
|
53
32
|
method = 'eth_call'
|
54
33
|
params = [{ to: contract_address,
|
@@ -56,23 +35,30 @@
|
|
56
35
|
'latest']
|
57
36
|
response = rpc.request( method, params )
|
58
37
|
|
38
|
+
if debug?
|
39
|
+
puts "response:"
|
40
|
+
pp response
|
41
|
+
end
|
59
42
|
|
60
|
-
|
61
|
-
|
43
|
+
bin = Utils.decode_hex( response )
|
44
|
+
return nil if bin.empty?
|
62
45
|
|
63
|
-
|
64
|
-
Utils.remove_0x_head(response))
|
65
|
-
return nil if string_data.empty?
|
46
|
+
result = ABI.decode( @output_types, bin )
|
66
47
|
|
67
|
-
result = Abi.decode_abi( @output_types, string_data )
|
68
|
-
puts
|
69
|
-
puts "result decode_abi:"
|
70
|
-
pp result
|
71
48
|
|
49
|
+
if debug?
|
50
|
+
puts
|
51
|
+
puts "result decode_abi:"
|
52
|
+
pp result
|
53
|
+
end
|
72
54
|
|
73
55
|
result.length==1 ? result.first : result
|
74
56
|
end
|
75
57
|
|
58
|
+
####
|
59
|
+
# private helpers
|
60
|
+
def debug?() Ethlite.debug?; end ## forward to global Ethlite config
|
76
61
|
end # class ContractMethod
|
62
|
+
|
77
63
|
end # module Ethlite
|
78
64
|
|
data/lib/ethlite/utils.rb
CHANGED
@@ -1,225 +1,36 @@
|
|
1
1
|
module Ethlite
|
2
2
|
|
3
3
|
|
4
|
-
module
|
5
|
-
|
6
|
-
# Not the keccak in sha3, although it's underlying lib named SHA3
|
7
|
-
#
|
8
|
-
def keccak256(x)
|
4
|
+
module Helpers
|
5
|
+
def keccak256( bin )
|
9
6
|
# Digest::SHA3.new(256).digest(x)
|
10
7
|
## Digest::Keccak.digest(x, 256)
|
11
|
-
Digest::KeccakLite.new(256).digest(
|
8
|
+
Digest::KeccakLite.new(256).digest( bin )
|
12
9
|
end
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
Digest::KeccakLite.new(512).digest( x )
|
11
|
+
def encode_hex( bin ) ## bin_to_hex
|
12
|
+
raise TypeError, "Value must be a string" unless bin.is_a?( String )
|
13
|
+
## note: always return a hex string with default encoding e.g. utf-8 - why? why not?
|
14
|
+
bin.unpack("H*").first.force_encoding( Encoding::UTF_8 )
|
19
15
|
end
|
16
|
+
alias_method :bin_to_hex, :encode_hex
|
20
17
|
|
18
|
+
def decode_hex( hex ) ## hex_to_bin
|
19
|
+
raise TypeError, "Value must be a string" unless hex.is_a?( String )
|
20
|
+
raise TypeError, 'Non-hexadecimal char found' unless hex.empty? || hex =~ /\A(0x)?[0-9a-fA-F]{2,}\z/
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
def sha256(x)
|
27
|
-
Digest::SHA256.digest x
|
28
|
-
end
|
29
|
-
|
30
|
-
def double_sha256(x)
|
31
|
-
sha256 sha256(x)
|
32
|
-
end
|
33
|
-
|
34
|
-
def ripemd160(x)
|
35
|
-
Digest::RMD160.digest x
|
36
|
-
end
|
37
|
-
|
38
|
-
def hash160(x)
|
39
|
-
ripemd160 sha256(x)
|
40
|
-
end
|
41
|
-
|
42
|
-
def hash160_hex(x)
|
43
|
-
encode_hex hash160(x)
|
44
|
-
end
|
45
|
-
|
46
|
-
def mod_exp(x, y, n)
|
47
|
-
x.to_bn.mod_exp(y, n).to_i
|
48
|
-
end
|
49
|
-
|
50
|
-
def mod_mul(x, y, n)
|
51
|
-
x.to_bn.mod_mul(y, n).to_i
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_signed(i)
|
55
|
-
i > INT_MAX ? (i-TT256) : i
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
def ceil32(x)
|
60
|
-
x % 32 == 0 ? x : (x + 32 - x%32)
|
61
|
-
end
|
62
|
-
|
63
|
-
def encode_hex(b)
|
64
|
-
raise TypeError, "Value must be an instance of String" unless b.instance_of?(String)
|
65
|
-
b.unpack("H*").first
|
66
|
-
end
|
67
|
-
|
68
|
-
def decode_hex(str)
|
69
|
-
raise TypeError, "Value must be an instance of string" unless str.instance_of?(String)
|
70
|
-
raise TypeError, 'Non-hexadecimal digit found' unless str =~ /\A[0-9a-fA-F]*\z/
|
71
|
-
[str].pack("H*")
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
def int_to_big_endian(n)
|
78
|
-
RLP::Sedes.big_endian_int.serialize n
|
79
|
-
end
|
80
|
-
|
81
|
-
def big_endian_to_int(s)
|
82
|
-
RLP::Sedes.big_endian_int.deserialize s.sub(/\A(\x00)+/, '')
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
def encode_int(n)
|
87
|
-
raise ArgumentError, "Integer invalid or out of range: #{n}" unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
88
|
-
int_to_big_endian n
|
89
|
-
end
|
90
|
-
|
91
|
-
def decode_int(v)
|
92
|
-
raise ArgumentError, "No leading zero bytes allowed for integers" if v.size > 0 && (v[0] == BYTE_ZERO || v[0] == 0)
|
93
|
-
big_endian_to_int v
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
def lpad(x, symbol, l)
|
100
|
-
return x if x.size >= l
|
101
|
-
symbol * (l - x.size) + x
|
102
|
-
end
|
103
|
-
|
104
|
-
def rpad(x, symbol, l)
|
105
|
-
return x if x.size >= l
|
106
|
-
x + symbol * (l - x.size)
|
107
|
-
end
|
108
|
-
|
109
|
-
def zpad(x, l)
|
110
|
-
lpad x, BYTE_ZERO, l
|
111
|
-
end
|
112
|
-
|
113
|
-
def zunpad(x)
|
114
|
-
x.sub /\A\x00+/, ''
|
115
|
-
end
|
116
|
-
|
117
|
-
def zpad_int(n, l=32)
|
118
|
-
zpad encode_int(n), l
|
119
|
-
end
|
120
|
-
|
121
|
-
def zpad_hex(s, l=32)
|
122
|
-
zpad decode_hex(s), l
|
123
|
-
end
|
124
|
-
|
125
|
-
def int_to_addr(x)
|
126
|
-
zpad_int x, 20
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
def bytearray_to_int(arr)
|
131
|
-
o = 0
|
132
|
-
arr.each {|x| o = (o << 8) + x }
|
133
|
-
o
|
134
|
-
end
|
135
|
-
|
136
|
-
def int_array_to_bytes(arr)
|
137
|
-
arr.pack('C*')
|
138
|
-
end
|
139
|
-
|
140
|
-
def bytes_to_int_array(bytes)
|
141
|
-
bytes.unpack('C*')
|
142
|
-
end
|
22
|
+
## allow optional starting 0x - why? why not?
|
23
|
+
hex = hex[2..-1] if hex[0,2] == '0x'
|
143
24
|
|
144
|
-
|
145
|
-
def coerce_to_int(x)
|
146
|
-
if x.is_a?(Numeric)
|
147
|
-
x
|
148
|
-
elsif x.size == 40
|
149
|
-
big_endian_to_int decode_hex(x)
|
150
|
-
else
|
151
|
-
big_endian_to_int x
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def coerce_to_bytes(x)
|
156
|
-
if x.is_a?(Numeric)
|
157
|
-
int_to_big_endian x
|
158
|
-
elsif x.size == 40
|
159
|
-
decode_hex(x)
|
160
|
-
else
|
161
|
-
x
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
def coerce_addr_to_hex(x)
|
166
|
-
if x.is_a?(Numeric)
|
167
|
-
encode_hex zpad(int_to_big_endian(x), 20)
|
168
|
-
elsif x.size == 40 || x.size == 0
|
169
|
-
x
|
170
|
-
else
|
171
|
-
encode_hex zpad(x, 20)[-20..-1]
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
def parse_int_or_hex(s)
|
178
|
-
if s.is_a?(Numeric)
|
179
|
-
s
|
180
|
-
elsif s[0,2] == '0x'
|
181
|
-
big_endian_to_int decode_hex(normalize_hex_without_prefix(s))
|
182
|
-
else
|
183
|
-
s.to_i
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
|
188
|
-
=begin
|
189
|
-
## add? moved over from the old module Utility
|
190
|
-
def hex( num )
|
191
|
-
'0x' + num.to_s(16)
|
192
|
-
end
|
193
|
-
|
194
|
-
def from_hex( h )
|
195
|
-
h.nil? ? 0 : (h.kind_of?(String) ? h.to_i(16) : h)
|
196
|
-
end
|
197
|
-
=end
|
198
|
-
|
199
|
-
|
200
|
-
def remove_0x_head( s )
|
201
|
-
return s if !s || s.length<2
|
202
|
-
s[0,2] == '0x' ? s[2..-1] : s
|
25
|
+
[hex].pack("H*")
|
203
26
|
end
|
204
|
-
|
205
|
-
|
206
|
-
if s[0,2] == '0x'
|
207
|
-
(s.size % 2 == 1 ? '0' : '') + s[2..-1]
|
208
|
-
else
|
209
|
-
s
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def signature_hash( signature, length=8 )
|
214
|
-
encode_hex( keccak256(signature) )[0...length]
|
215
|
-
end
|
216
|
-
|
217
|
-
end # module UtilHelper
|
27
|
+
alias_method :hex_to_bin, :decode_hex
|
28
|
+
end # module Helpers
|
218
29
|
|
219
30
|
|
220
31
|
|
221
32
|
module Utils
|
222
|
-
extend
|
33
|
+
extend Helpers
|
223
34
|
end
|
224
35
|
|
225
36
|
end # module Ethlite
|
data/lib/ethlite/version.rb
CHANGED
data/lib/ethlite.rb
CHANGED
@@ -19,18 +19,14 @@ end
|
|
19
19
|
load_env
|
20
20
|
|
21
21
|
|
22
|
-
require 'uri'
|
23
|
-
require 'net/http'
|
24
|
-
require 'net/https'
|
25
|
-
require 'json'
|
26
|
-
|
27
22
|
|
28
23
|
require 'openssl'
|
29
24
|
require 'digest'
|
30
25
|
|
26
|
+
|
31
27
|
## 3rd party gems
|
32
|
-
require 'rlp-lite'
|
33
28
|
require 'digest-lite'
|
29
|
+
require 'abicoder'
|
34
30
|
|
35
31
|
|
36
32
|
require_relative 'jsonrpc/jsonrpc'
|
@@ -38,15 +34,7 @@ require_relative 'jsonrpc/jsonrpc'
|
|
38
34
|
|
39
35
|
## our own code
|
40
36
|
require_relative 'ethlite/version' # note: let version always go first
|
41
|
-
|
42
|
-
require_relative 'ethlite/constant'
|
43
37
|
require_relative 'ethlite/utils'
|
44
|
-
|
45
|
-
|
46
|
-
require_relative 'ethlite/abi/type'
|
47
|
-
require_relative 'ethlite/abi/codec'
|
48
|
-
|
49
|
-
|
50
38
|
require_relative 'ethlite/contract'
|
51
39
|
|
52
40
|
|
@@ -61,6 +49,10 @@ class Configuration
|
|
61
49
|
value
|
62
50
|
end
|
63
51
|
end
|
52
|
+
|
53
|
+
## add "global" debug switch - why? why not?
|
54
|
+
def debug?() (@debug || false) == true; end
|
55
|
+
def debug=(value) @debug = value; end
|
64
56
|
end # class Configuration
|
65
57
|
|
66
58
|
|
@@ -70,6 +62,9 @@ end # class Configuration
|
|
70
62
|
## end
|
71
63
|
def self.configure() yield( config ); end
|
72
64
|
def self.config() @config ||= Configuration.new; end
|
65
|
+
|
66
|
+
## add debug convenience config shortcut - forwarding to config.debug? - why? why not?
|
67
|
+
def self.debug?() config.debug?; end
|
73
68
|
end # module Ethlite
|
74
69
|
|
75
70
|
|
data/lib/jsonrpc/jsonrpc.rb
CHANGED
@@ -8,6 +8,16 @@
|
|
8
8
|
|
9
9
|
|
10
10
|
class JsonRpc
|
11
|
+
|
12
|
+
### add a global debug switch - why? why not?
|
13
|
+
def self.debug?() (@debug || false) == true; end
|
14
|
+
def self.debug( value ) @debug = value; end
|
15
|
+
####
|
16
|
+
# private helpers
|
17
|
+
def debug?() self.class.debug?; end
|
18
|
+
|
19
|
+
|
20
|
+
|
11
21
|
def initialize( uri )
|
12
22
|
@uri = uri ## assume uri always as string for now
|
13
23
|
@request_id = 1
|
@@ -23,8 +33,10 @@ class JsonRpc
|
|
23
33
|
|
24
34
|
@request_id += 1
|
25
35
|
|
26
|
-
|
27
|
-
|
36
|
+
if debug?
|
37
|
+
puts "json_rpc POST payload:"
|
38
|
+
puts data.to_json
|
39
|
+
end
|
28
40
|
|
29
41
|
response = Webclient.post( @uri, json: data )
|
30
42
|
|
@@ -33,8 +45,10 @@ class JsonRpc
|
|
33
45
|
raise "Error code #{response.status.code} on request #{@uri} #{data}"
|
34
46
|
end
|
35
47
|
|
36
|
-
|
37
|
-
|
48
|
+
if debug?
|
49
|
+
puts "json_rpc response.body:"
|
50
|
+
puts response.body
|
51
|
+
end
|
38
52
|
|
39
53
|
|
40
54
|
body = JSON.parse( response.body, max_nesting: 1500 )
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ethlite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cocos
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: digest-lite
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: abicoder
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -101,9 +101,6 @@ files:
|
|
101
101
|
- README.md
|
102
102
|
- Rakefile
|
103
103
|
- lib/ethlite.rb
|
104
|
-
- lib/ethlite/abi/codec.rb
|
105
|
-
- lib/ethlite/abi/type.rb
|
106
|
-
- lib/ethlite/constant.rb
|
107
104
|
- lib/ethlite/contract.rb
|
108
105
|
- lib/ethlite/utils.rb
|
109
106
|
- lib/ethlite/version.rb
|
data/lib/ethlite/abi/codec.rb
DELETED
@@ -1,436 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Ethlite
|
4
|
-
module Abi
|
5
|
-
|
6
|
-
##
|
7
|
-
# Contract ABI encoding and decoding.
|
8
|
-
#
|
9
|
-
# @see https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
10
|
-
#
|
11
|
-
class Codec
|
12
|
-
class EncodingError < StandardError; end
|
13
|
-
class DecodingError < StandardError; end
|
14
|
-
class ValueError < StandardError; end
|
15
|
-
|
16
|
-
class ValueOutOfBounds < ValueError; end
|
17
|
-
|
18
|
-
##
|
19
|
-
# Encodes multiple arguments using the head/tail mechanism.
|
20
|
-
#
|
21
|
-
def encode_abi(types, args)
|
22
|
-
parsed_types = types.map {|t| Type.parse(t) }
|
23
|
-
|
24
|
-
head_size = (0...args.size)
|
25
|
-
.map {|i| parsed_types[i].size || 32 }
|
26
|
-
.reduce(0, &:+)
|
27
|
-
|
28
|
-
head, tail = '', ''
|
29
|
-
args.each_with_index do |arg, i|
|
30
|
-
if parsed_types[i].dynamic?
|
31
|
-
head += encode_type(Type.size_type, head_size + tail.size)
|
32
|
-
tail += encode_type(parsed_types[i], arg)
|
33
|
-
else
|
34
|
-
head += encode_type(parsed_types[i], arg)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
"#{head}#{tail}"
|
39
|
-
end
|
40
|
-
|
41
|
-
##
|
42
|
-
# Encodes a single value (static or dynamic).
|
43
|
-
#
|
44
|
-
# @param type [Ethereum::ABI::Type] value type
|
45
|
-
# @param arg [Object] value
|
46
|
-
#
|
47
|
-
# @return [String] encoded bytes
|
48
|
-
#
|
49
|
-
def encode_type(type, arg)
|
50
|
-
if %w(string bytes).include?(type.base) && type.sub.empty?
|
51
|
-
encode_primitive_type type, arg
|
52
|
-
elsif type.dynamic?
|
53
|
-
raise ArgumentError, "arg must be an array" unless arg.instance_of?(Array)
|
54
|
-
|
55
|
-
head, tail = '', ''
|
56
|
-
if type.dims.last == 0
|
57
|
-
head += encode_type(Type.size_type, arg.size)
|
58
|
-
else
|
59
|
-
raise ArgumentError, "Wrong array size: found #{arg.size}, expecting #{type.dims.last}" unless arg.size == type.dims.last
|
60
|
-
end
|
61
|
-
|
62
|
-
sub_type = type.subtype
|
63
|
-
sub_size = type.subtype.size
|
64
|
-
arg.size.times do |i|
|
65
|
-
if sub_size.nil?
|
66
|
-
head += encode_type(Type.size_type, 32*arg.size + tail.size)
|
67
|
-
tail += encode_type(sub_type, arg[i])
|
68
|
-
else
|
69
|
-
head += encode_type(sub_type, arg[i])
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
"#{head}#{tail}"
|
74
|
-
else # static type
|
75
|
-
if type.dims.empty?
|
76
|
-
encode_primitive_type type, arg
|
77
|
-
else
|
78
|
-
arg.map {|x| encode_type(type.subtype, x) }.join
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def encode_primitive_type(type, arg)
|
84
|
-
case type.base
|
85
|
-
when 'uint'
|
86
|
-
begin
|
87
|
-
real_size = type.sub.to_i
|
88
|
-
i = get_uint arg
|
89
|
-
|
90
|
-
raise ValueOutOfBounds, arg unless i >= 0 && i < 2**real_size
|
91
|
-
Utils.zpad_int i
|
92
|
-
rescue EncodingError
|
93
|
-
raise ValueOutOfBounds, arg
|
94
|
-
end
|
95
|
-
when 'bool'
|
96
|
-
raise ArgumentError, "arg is not bool: #{arg}" unless arg.instance_of?(TrueClass) || arg.instance_of?(FalseClass)
|
97
|
-
Utils.zpad_int(arg ? 1 : 0)
|
98
|
-
when 'int'
|
99
|
-
begin
|
100
|
-
real_size = type.sub.to_i
|
101
|
-
i = get_int arg
|
102
|
-
|
103
|
-
raise ValueOutOfBounds, arg unless i >= -2**(real_size-1) && i < 2**(real_size-1)
|
104
|
-
Utils.zpad_int(i % 2**type.sub.to_i)
|
105
|
-
rescue EncodingError
|
106
|
-
raise ValueOutOfBounds, arg
|
107
|
-
end
|
108
|
-
when 'ufixed'
|
109
|
-
high, low = type.sub.split('x').map(&:to_i)
|
110
|
-
|
111
|
-
raise ValueOutOfBounds, arg unless arg >= 0 && arg < 2**high
|
112
|
-
Utils.zpad_int((arg * 2**low).to_i)
|
113
|
-
when 'fixed'
|
114
|
-
high, low = type.sub.split('x').map(&:to_i)
|
115
|
-
|
116
|
-
raise ValueOutOfBounds, arg unless arg >= -2**(high - 1) && arg < 2**(high - 1)
|
117
|
-
|
118
|
-
i = (arg * 2**low).to_i
|
119
|
-
Utils.zpad_int(i % 2**(high+low))
|
120
|
-
when 'string'
|
121
|
-
if arg.encoding.name == 'UTF-8'
|
122
|
-
arg = arg.b
|
123
|
-
else
|
124
|
-
begin
|
125
|
-
arg.unpack('U*')
|
126
|
-
rescue ArgumentError
|
127
|
-
raise ValueError, "string must be UTF-8 encoded"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
if type.sub.empty? # variable length type
|
132
|
-
raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
|
133
|
-
size = Utils.zpad_int arg.size
|
134
|
-
value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
|
135
|
-
"#{size}#{value}"
|
136
|
-
else # fixed length type
|
137
|
-
sub = type.sub.to_i
|
138
|
-
raise ValueOutOfBounds, "invalid string length #{sub}" if arg.size > sub
|
139
|
-
raise ValueOutOfBounds, "invalid string length #{sub}" if sub < 0 || sub > 32
|
140
|
-
Utils.rpad(arg, BYTE_ZERO, 32)
|
141
|
-
end
|
142
|
-
when 'bytes'
|
143
|
-
raise EncodingError, "Expecting string: #{arg}" unless arg.instance_of?(String)
|
144
|
-
arg = arg.b
|
145
|
-
|
146
|
-
if type.sub.empty? # variable length type
|
147
|
-
raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
|
148
|
-
size = Utils.zpad_int arg.size
|
149
|
-
value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
|
150
|
-
"#{size}#{value}"
|
151
|
-
else # fixed length type
|
152
|
-
sub = type.sub.to_i
|
153
|
-
raise ValueOutOfBounds, "invalid bytes length #{sub}" if arg.size > sub
|
154
|
-
raise ValueOutOfBounds, "invalid bytes length #{sub}" if sub < 0 || sub > 32
|
155
|
-
Utils.rpad(arg, BYTE_ZERO, 32)
|
156
|
-
end
|
157
|
-
when 'hash'
|
158
|
-
size = type.sub.to_i
|
159
|
-
raise EncodingError, "too long: #{arg}" unless size > 0 && size <= 32
|
160
|
-
|
161
|
-
if arg.is_a?(Integer)
|
162
|
-
Utils.zpad_int(arg)
|
163
|
-
elsif arg.size == size
|
164
|
-
Utils.zpad arg, 32
|
165
|
-
elsif arg.size == size * 2
|
166
|
-
Utils.zpad_hex arg
|
167
|
-
else
|
168
|
-
raise EncodingError, "Could not parse hash: #{arg}"
|
169
|
-
end
|
170
|
-
when 'address'
|
171
|
-
if arg.is_a?(Integer)
|
172
|
-
Utils.zpad_int arg
|
173
|
-
elsif arg.size == 20
|
174
|
-
Utils.zpad arg, 32
|
175
|
-
elsif arg.size == 40
|
176
|
-
Utils.zpad_hex arg
|
177
|
-
elsif arg.size == 42 && arg[0,2] == '0x'
|
178
|
-
Utils.zpad_hex arg[2..-1]
|
179
|
-
else
|
180
|
-
raise EncodingError, "Could not parse address: #{arg}"
|
181
|
-
end
|
182
|
-
else
|
183
|
-
raise EncodingError, "Unhandled type: #{type.base} #{type.sub}"
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
|
188
|
-
def min_data_size types
|
189
|
-
types.size*32
|
190
|
-
end
|
191
|
-
|
192
|
-
##
|
193
|
-
# Decodes multiple arguments using the head/tail mechanism.
|
194
|
-
#
|
195
|
-
def decode_abi types, data, raise_errors = false
|
196
|
-
parsed_types = types.map {|t| Type.parse(t) }
|
197
|
-
|
198
|
-
outputs = [nil] * types.size
|
199
|
-
start_positions = [nil] * types.size + [data.size]
|
200
|
-
|
201
|
-
# TODO: refactor, a reverse iteration will be better
|
202
|
-
pos = 0
|
203
|
-
parsed_types.each_with_index do |t, i|
|
204
|
-
# If a type is static, grab the data directly, otherwise record its
|
205
|
-
# start position
|
206
|
-
if t.dynamic?
|
207
|
-
|
208
|
-
if raise_errors && pos>data.size-1
|
209
|
-
raise DecodingError, "Position out of bounds #{pos}>#{data.size-1}"
|
210
|
-
end
|
211
|
-
|
212
|
-
start_positions[i] = Utils.big_endian_to_int(data[pos, 32])
|
213
|
-
|
214
|
-
if raise_errors && start_positions[i]>data.size-1
|
215
|
-
raise DecodingError, "Start position out of bounds #{start_positions[i]}>#{data.size-1}"
|
216
|
-
end
|
217
|
-
|
218
|
-
j = i - 1
|
219
|
-
while j >= 0 && start_positions[j].nil?
|
220
|
-
start_positions[j] = start_positions[i]
|
221
|
-
j -= 1
|
222
|
-
end
|
223
|
-
|
224
|
-
pos += 32
|
225
|
-
else
|
226
|
-
outputs[i] = zero_padding data, pos, t.size, start_positions
|
227
|
-
pos += t.size
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
# We add a start position equal to the length of the entire data for
|
232
|
-
# convenience.
|
233
|
-
j = types.size - 1
|
234
|
-
while j >= 0 && start_positions[j].nil?
|
235
|
-
start_positions[j] = start_positions[types.size]
|
236
|
-
j -= 1
|
237
|
-
end
|
238
|
-
|
239
|
-
if raise_errors && pos > data.size
|
240
|
-
raise DecodingError, "Not enough data for head"
|
241
|
-
end
|
242
|
-
|
243
|
-
|
244
|
-
parsed_types.each_with_index do |t, i|
|
245
|
-
if t.dynamic?
|
246
|
-
offset, next_offset = start_positions[i, 2]
|
247
|
-
if offset<=data.size && next_offset<=data.size
|
248
|
-
outputs[i] = data[offset...next_offset]
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
if raise_errors && outputs.include?(nil)
|
254
|
-
raise DecodingError, "Not all data can be parsed"
|
255
|
-
end
|
256
|
-
|
257
|
-
parsed_types.zip(outputs).map {|(type, out)| decode_type(type, out) }
|
258
|
-
end
|
259
|
-
|
260
|
-
|
261
|
-
def zero_padding data, pos, count, start_positions
|
262
|
-
if pos >= data.size
|
263
|
-
start_positions[start_positions.size-1] += count
|
264
|
-
"\x00"*count
|
265
|
-
elsif pos + count > data.size
|
266
|
-
start_positions[start_positions.size-1] += ( count - (data.size-pos))
|
267
|
-
data[pos,data.size-pos] + "\x00"*( count - (data.size-pos))
|
268
|
-
else
|
269
|
-
data[pos, count]
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
def decode_typed_data type_name, data
|
274
|
-
decode_primitive_type Type.parse(type_name), data
|
275
|
-
end
|
276
|
-
|
277
|
-
def decode_type(type, arg)
|
278
|
-
return nil if arg.nil? || arg.empty?
|
279
|
-
if type.kind_of?(Tuple) && type.dims.empty?
|
280
|
-
arg ? decode_abi(type.types, arg) : []
|
281
|
-
elsif %w(string bytes).include?(type.base) && type.sub.empty?
|
282
|
-
l = Utils.big_endian_to_int arg[0,32]
|
283
|
-
data = arg[32..-1]
|
284
|
-
data[0, l]
|
285
|
-
elsif !type.dims.empty? && (l = type.dims.last)>0 # static-sized arrays
|
286
|
-
subtype = type.subtype
|
287
|
-
if subtype.dynamic?
|
288
|
-
start_positions = (0...l).map {|i| Utils.big_endian_to_int(arg[32*i, 32]) }
|
289
|
-
start_positions.push arg.size
|
290
|
-
|
291
|
-
outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
|
292
|
-
|
293
|
-
outputs.map {|out| decode_type(subtype, out) }
|
294
|
-
else
|
295
|
-
(0...l).map {|i| decode_type(subtype, arg[subtype.size*i, subtype.size]) }
|
296
|
-
end
|
297
|
-
|
298
|
-
elsif type.dynamic?
|
299
|
-
l = Utils.big_endian_to_int arg[0,32]
|
300
|
-
raise DecodingError, "Too long length: #{l}" if l>100000
|
301
|
-
subtype = type.subtype
|
302
|
-
|
303
|
-
if subtype.dynamic?
|
304
|
-
raise DecodingError, "Not enough data for head" unless arg.size >= 32 + 32*l
|
305
|
-
|
306
|
-
start_positions = (1..l).map {|i| 32+Utils.big_endian_to_int(arg[32*i, 32]) }
|
307
|
-
start_positions.push arg.size
|
308
|
-
|
309
|
-
outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
|
310
|
-
|
311
|
-
outputs.map {|out| decode_type(subtype, out) }
|
312
|
-
else
|
313
|
-
(0...l).map {|i| decode_type(subtype, arg[32 + subtype.size*i, subtype.size]) }
|
314
|
-
end
|
315
|
-
|
316
|
-
else
|
317
|
-
decode_primitive_type type, arg
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
def decode_primitive_type(type, data)
|
322
|
-
case type.base
|
323
|
-
when 'address'
|
324
|
-
Utils.encode_hex data[12..-1]
|
325
|
-
when 'string', 'bytes'
|
326
|
-
if type.sub.empty? # dynamic
|
327
|
-
if data.length==32
|
328
|
-
data[0..32]
|
329
|
-
else
|
330
|
-
size = Utils.big_endian_to_int data[0,32]
|
331
|
-
data[32..-1][0,size]
|
332
|
-
end
|
333
|
-
else # fixed
|
334
|
-
data[0, type.sub.to_i]
|
335
|
-
end
|
336
|
-
when 'hash'
|
337
|
-
data[(32 - type.sub.to_i), type.sub.to_i]
|
338
|
-
when 'uint'
|
339
|
-
Utils.big_endian_to_int data
|
340
|
-
when 'int'
|
341
|
-
u = Utils.big_endian_to_int data
|
342
|
-
u >= 2**(type.sub.to_i-1) ? (u - 2**type.sub.to_i) : u
|
343
|
-
when 'ufixed'
|
344
|
-
high, low = type.sub.split('x').map(&:to_i)
|
345
|
-
Utils.big_endian_to_int(data) * 1.0 / 2**low
|
346
|
-
when 'fixed'
|
347
|
-
high, low = type.sub.split('x').map(&:to_i)
|
348
|
-
u = Utils.big_endian_to_int data
|
349
|
-
i = u >= 2**(high+low-1) ? (u - 2**(high+low)) : u
|
350
|
-
i * 1.0 / 2**low
|
351
|
-
when 'bool'
|
352
|
-
data[-1] == BYTE_ONE
|
353
|
-
else
|
354
|
-
raise DecodingError, "Unknown primitive type: #{type.base}"
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
private
|
359
|
-
|
360
|
-
def get_uint(n)
|
361
|
-
case n
|
362
|
-
when Integer
|
363
|
-
raise EncodingError, "Number out of range: #{n}" if n > UINT_MAX || n < UINT_MIN
|
364
|
-
n
|
365
|
-
when String
|
366
|
-
i = if n.size == 40
|
367
|
-
Utils.decode_hex(n)
|
368
|
-
elsif n.size <= 32
|
369
|
-
n
|
370
|
-
else
|
371
|
-
raise EncodingError, "String too long: #{n}"
|
372
|
-
end
|
373
|
-
i = Utils.big_endian_to_int i
|
374
|
-
|
375
|
-
raise EncodingError, "Number out of range: #{i}" if i > UINT_MAX || i < UINT_MIN
|
376
|
-
i
|
377
|
-
when true
|
378
|
-
1
|
379
|
-
when false, nil
|
380
|
-
0
|
381
|
-
else
|
382
|
-
raise EncodingError, "Cannot decode uint: #{n}"
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
def get_int(n)
|
387
|
-
case n
|
388
|
-
when Integer
|
389
|
-
raise EncodingError, "Number out of range: #{n}" if n > INT_MAX || n < INT_MIN
|
390
|
-
n
|
391
|
-
when String
|
392
|
-
i = if n.size == 40
|
393
|
-
Utils.decode_hex(n)
|
394
|
-
elsif n.size <= 32
|
395
|
-
n
|
396
|
-
else
|
397
|
-
raise EncodingError, "String too long: #{n}"
|
398
|
-
end
|
399
|
-
i = Utils.big_endian_to_int i
|
400
|
-
|
401
|
-
i = i > INT_MAX ? (i-TT256) : i
|
402
|
-
raise EncodingError, "Number out of range: #{i}" if i > INT_MAX || i < INT_MIN
|
403
|
-
i
|
404
|
-
when true
|
405
|
-
1
|
406
|
-
when false, nil
|
407
|
-
0
|
408
|
-
else
|
409
|
-
raise EncodingError, "Cannot decode int: #{n}"
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end # class Codec
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
def self.codec
|
420
|
-
@codec ||= Codec.new
|
421
|
-
end
|
422
|
-
|
423
|
-
def self.encode_abi(types, args)
|
424
|
-
codec.encode_abi( types, args )
|
425
|
-
end
|
426
|
-
|
427
|
-
def self.decode_abi(types, data, raise_errors = false)
|
428
|
-
codec.decode_abi( types, data, raise_errors )
|
429
|
-
end
|
430
|
-
|
431
|
-
|
432
|
-
end # module Abi
|
433
|
-
end # module Ethlite
|
434
|
-
|
435
|
-
|
436
|
-
|
data/lib/ethlite/abi/type.rb
DELETED
@@ -1,200 +0,0 @@
|
|
1
|
-
module Ethlite
|
2
|
-
module Abi
|
3
|
-
class Type
|
4
|
-
|
5
|
-
class ParseError < StandardError; end
|
6
|
-
|
7
|
-
|
8
|
-
##
|
9
|
-
# Crazy regexp to seperate out base type component (eg. uint), size (eg.
|
10
|
-
# 256, 128x128, nil), array component (eg. [], [45], nil)
|
11
|
-
#
|
12
|
-
def self.parse( type )
|
13
|
-
|
14
|
-
return parse('uint256') if type=='trcToken'
|
15
|
-
|
16
|
-
if type =~ /^\((.*)\)((\[[0-9]*\])*)/
|
17
|
-
return Tuple.parse $1, $2.scan(/\[[0-9]*\]/)
|
18
|
-
end
|
19
|
-
|
20
|
-
_, base, sub, dimension = /([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)/.match(type).to_a
|
21
|
-
|
22
|
-
dims = dimension.scan(/\[[0-9]*\]/)
|
23
|
-
raise ParseError, "Unknown characters found in array declaration" if dims.join != dimension
|
24
|
-
|
25
|
-
case base
|
26
|
-
when ''
|
27
|
-
return parse 'address'
|
28
|
-
when 'bytes', 'string'
|
29
|
-
raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub.empty? || sub.to_i <= 32
|
30
|
-
when 'uint', 'int'
|
31
|
-
raise ParseError, "Integer type must have numerical suffix" unless sub =~ /\A[0-9]+\z/
|
32
|
-
|
33
|
-
size = sub.to_i
|
34
|
-
raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256
|
35
|
-
raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
|
36
|
-
when 'fixed', 'ufixed'
|
37
|
-
raise ParseError, "Fixed type must have suffix of form <high>x<low>, e.g. 128x128" unless sub =~ /\A[0-9]+x[0-9]+\z/
|
38
|
-
|
39
|
-
high, low = sub.split('x').map(&:to_i)
|
40
|
-
total = high + low
|
41
|
-
|
42
|
-
raise ParseError, "Fixed size out of bounds (max 32 bytes)" unless total >= 8 && total <= 256
|
43
|
-
raise ParseError, "Fixed high size must be multiple of 8" unless high % 8 == 0
|
44
|
-
raise ParseError, "Low sizes must be 0 to 80" unless low>0 && low<=80
|
45
|
-
when 'hash'
|
46
|
-
raise ParseError, "Hash type must have numerical suffix" unless sub =~ /\A[0-9]+\z/
|
47
|
-
when 'address'
|
48
|
-
raise ParseError, "Address cannot have suffix" unless sub.empty?
|
49
|
-
when 'bool'
|
50
|
-
raise ParseError, "Bool cannot have suffix" unless sub.empty?
|
51
|
-
else
|
52
|
-
raise ParseError, "Unrecognized type base: #{base}"
|
53
|
-
end
|
54
|
-
|
55
|
-
new(base, sub, dims.map {|x| x[1...-1].to_i})
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.size_type
|
59
|
-
@size_type ||= new('uint', 256, [])
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
attr :base, :sub, :dims
|
64
|
-
|
65
|
-
##
|
66
|
-
# @param base [String] base name of type, e.g. uint for uint256[4]
|
67
|
-
# @param sub [String] subscript of type, e.g. 256 for uint256[4]
|
68
|
-
# @param dims [Array[Integer]] dimensions of array type, e.g. [1,2,0]
|
69
|
-
# for uint256[1][2][], [] for non-array type
|
70
|
-
#
|
71
|
-
def initialize( base, sub, dims )
|
72
|
-
@base = base
|
73
|
-
@sub = sub
|
74
|
-
@dims = dims
|
75
|
-
end
|
76
|
-
|
77
|
-
def ==(another_type)
|
78
|
-
base == another_type.base &&
|
79
|
-
sub == another_type.sub &&
|
80
|
-
dims == another_type.dims
|
81
|
-
end
|
82
|
-
|
83
|
-
##
|
84
|
-
# Get the static size of a type, or nil if dynamic.
|
85
|
-
#
|
86
|
-
# @return [Integer, NilClass] size of static type, or nil for dynamic
|
87
|
-
# type
|
88
|
-
#
|
89
|
-
def size
|
90
|
-
@size ||= if dims.empty?
|
91
|
-
if %w(string bytes).include?(base) && sub.empty?
|
92
|
-
nil
|
93
|
-
else
|
94
|
-
32
|
95
|
-
end
|
96
|
-
else
|
97
|
-
if dims.last == 0 # 0 for dynamic array []
|
98
|
-
nil
|
99
|
-
else
|
100
|
-
subtype.dynamic? ? nil : dims.last * subtype.size
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def dynamic?
|
106
|
-
size.nil?
|
107
|
-
end
|
108
|
-
|
109
|
-
##
|
110
|
-
# Type with one dimension lesser.
|
111
|
-
#
|
112
|
-
# @example
|
113
|
-
# Type.parse("uint256[2][]").subtype # => Type.new('uint', 256, [2])
|
114
|
-
#
|
115
|
-
# @return [Ethereum::ABI::Type]
|
116
|
-
#
|
117
|
-
def subtype
|
118
|
-
@subtype ||= self.class.new(base, sub, dims[0...-1])
|
119
|
-
end
|
120
|
-
end # class Type
|
121
|
-
|
122
|
-
|
123
|
-
class Tuple < Type
|
124
|
-
|
125
|
-
def self.parse( types, dims )
|
126
|
-
|
127
|
-
depth = 0
|
128
|
-
collected = []
|
129
|
-
current = ''
|
130
|
-
|
131
|
-
types.split('').each do |c|
|
132
|
-
case c
|
133
|
-
when ',' then
|
134
|
-
if depth==0
|
135
|
-
collected << current
|
136
|
-
current = ''
|
137
|
-
else
|
138
|
-
current += c
|
139
|
-
end
|
140
|
-
when '(' then
|
141
|
-
depth += 1
|
142
|
-
current += c
|
143
|
-
when ')' then
|
144
|
-
depth -= 1
|
145
|
-
current += c
|
146
|
-
else
|
147
|
-
current += c
|
148
|
-
end
|
149
|
-
|
150
|
-
end
|
151
|
-
collected << current unless current.empty?
|
152
|
-
|
153
|
-
Tuple.new collected, dims.map {|x| x[1...-1].to_i}
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
attr_reader :types, :parsed_types
|
158
|
-
|
159
|
-
def initialize( types, dims )
|
160
|
-
super('tuple', '', dims)
|
161
|
-
@types = types
|
162
|
-
@parsed_types = types.map{|t| Type.parse t}
|
163
|
-
end
|
164
|
-
|
165
|
-
def ==(another_type)
|
166
|
-
another_type.kind_of?(Tuple) &&
|
167
|
-
another_type.types == types &&
|
168
|
-
another_type.dims == dims
|
169
|
-
end
|
170
|
-
|
171
|
-
def size
|
172
|
-
@size ||= calculate_size
|
173
|
-
end
|
174
|
-
|
175
|
-
def calculate_size
|
176
|
-
if dims.empty?
|
177
|
-
s = 0
|
178
|
-
parsed_types.each do |type|
|
179
|
-
ts = type.size
|
180
|
-
return nil if ts.nil?
|
181
|
-
s += ts
|
182
|
-
end
|
183
|
-
s
|
184
|
-
else
|
185
|
-
if dims.last == 0 # 0 for dynamic array []
|
186
|
-
nil
|
187
|
-
else
|
188
|
-
subtype.dynamic? ? nil : dims.last * subtype.size
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def subtype
|
194
|
-
@subtype ||= Tuple.new(types, dims[0...-1])
|
195
|
-
end
|
196
|
-
end # class Tuple
|
197
|
-
|
198
|
-
|
199
|
-
end # module Abi
|
200
|
-
end # module Ethlite
|
data/lib/ethlite/constant.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
|
2
|
-
module Ethlite
|
3
|
-
|
4
|
-
|
5
|
-
## todo/check - use encoding -ascii-8bit for source file or ? - why? why not?
|
6
|
-
## use #b/.b to ensure binary encoding? - why? why not?
|
7
|
-
|
8
|
-
## todo/check: use auto-freeze string literals magic comment - why? why not?
|
9
|
-
BYTE_EMPTY = "".b.freeze
|
10
|
-
BYTE_ZERO = "\x00".b.freeze
|
11
|
-
BYTE_ONE = "\x01".b.freeze
|
12
|
-
|
13
|
-
|
14
|
-
TT32 = 2**32
|
15
|
-
TT40 = 2**40
|
16
|
-
TT160 = 2**160
|
17
|
-
TT256 = 2**256
|
18
|
-
TT64M1 = 2**64 - 1
|
19
|
-
|
20
|
-
UINT_MAX = 2**256 - 1
|
21
|
-
UINT_MIN = 0
|
22
|
-
INT_MAX = 2**255 - 1
|
23
|
-
INT_MIN = -2**255
|
24
|
-
|
25
|
-
HASH_ZERO = ("\x00"*32).b.freeze
|
26
|
-
|
27
|
-
|
28
|
-
PUBKEY_ZERO = ("\x00"*32).b.freeze
|
29
|
-
PRIVKEY_ZERO = ("\x00"*32).b.freeze
|
30
|
-
|
31
|
-
PRIVKEY_ZERO_HEX = ('0'*64).freeze
|
32
|
-
|
33
|
-
CONTRACT_CODE_SIZE_LIMIT = 0x6000
|
34
|
-
|
35
|
-
end # module Ethlite
|