ethlite 0.2.2 → 0.2.4
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 +3 -5
- data/Rakefile +1 -1
- data/lib/digest/{keccak256.rb → keccak.rb} +32 -18
- data/lib/digest/sha3.rb +31 -21
- data/lib/ethlite/abi/abi_coder.rb +3 -0
- data/lib/ethlite/abi/type.rb +10 -13
- data/lib/ethlite/abi/utils.rb +51 -49
- data/lib/ethlite/constant.rb +38 -0
- data/lib/ethlite/contract.rb +39 -23
- data/lib/ethlite/version.rb +1 -1
- data/lib/ethlite.rb +14 -9
- data/lib/jsonrpc/jsonrpc.rb +48 -0
- metadata +6 -8
- data/lib/ethlite/abi/constant.rb +0 -32
- data/lib/ethlite/abi/exceptions.rb +0 -29
- data/lib/ethlite/rpc.rb +0 -48
- data/lib/ethlite/utility.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6a9601ad8c91c592541ffc721dbe9bbb8572683ef88c995a1bb810f7da79e33
|
4
|
+
data.tar.gz: 4ddf8c5a91c9a370e580bc9519f4d7c9832f863f31e4dfb8fa2b0505c2c6d6e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12d4cd45f40f8ecf3835f058e2ac5d4e9a9b361e3cd91fd5bca193e982c7fd726ff3ffab08ed7bedb543c3800e76808364c51f2992d4971816629ac170f700f6
|
7
|
+
data.tar.gz: 236164ce176d5b50187e7402729a895130354f929df269e3b9d7b04472300b1661b9992a5579ba53064cbe0b7aee95e21aeeaae65225519ca55707caad771533
|
data/Manifest.txt
CHANGED
@@ -2,15 +2,13 @@ CHANGELOG.md
|
|
2
2
|
Manifest.txt
|
3
3
|
README.md
|
4
4
|
Rakefile
|
5
|
-
lib/digest/
|
5
|
+
lib/digest/keccak.rb
|
6
6
|
lib/digest/sha3.rb
|
7
7
|
lib/ethlite.rb
|
8
8
|
lib/ethlite/abi/abi_coder.rb
|
9
|
-
lib/ethlite/abi/constant.rb
|
10
|
-
lib/ethlite/abi/exceptions.rb
|
11
9
|
lib/ethlite/abi/type.rb
|
12
10
|
lib/ethlite/abi/utils.rb
|
11
|
+
lib/ethlite/constant.rb
|
13
12
|
lib/ethlite/contract.rb
|
14
|
-
lib/ethlite/rpc.rb
|
15
|
-
lib/ethlite/utility.rb
|
16
13
|
lib/ethlite/version.rb
|
14
|
+
lib/jsonrpc/jsonrpc.rb
|
data/Rakefile
CHANGED
@@ -8,8 +8,15 @@
|
|
8
8
|
## require 'digest'
|
9
9
|
|
10
10
|
|
11
|
+
|
12
|
+
##
|
13
|
+
# note: use KeccakLite (or KeccakZero? KeccakSHA3?) instead of Keccak
|
14
|
+
# to allow usage of native w/ c-extension Keccak and "lite" version
|
15
|
+
|
16
|
+
|
17
|
+
|
11
18
|
module Digest
|
12
|
-
class
|
19
|
+
class KeccakLite < Digest::Class
|
13
20
|
PILN = [10, 7, 11, 17, 18, 3, 5, 16,
|
14
21
|
8, 21, 24, 4, 15, 23, 19, 13,
|
15
22
|
12, 2, 20, 14, 22, 9, 6, 1]
|
@@ -27,16 +34,18 @@ module Digest
|
|
27
34
|
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
28
35
|
0x8000000000008080, 0x0000000080000001, 0x8000000080008008]
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
## note: changed initialize to use param hash_size = 512
|
38
|
+
## do NOT hard-code only 256 bit
|
39
|
+
def initialize( hash_size = 512 )
|
40
|
+
@size = hash_size / 8
|
32
41
|
@buffer = ''
|
33
42
|
end
|
34
43
|
|
35
|
-
def << s
|
44
|
+
def <<( s )
|
36
45
|
@buffer << s
|
37
46
|
self
|
38
47
|
end
|
39
|
-
|
48
|
+
alias_method :update, :<<
|
40
49
|
|
41
50
|
def reset
|
42
51
|
@buffer.clear
|
@@ -44,37 +53,40 @@ module Digest
|
|
44
53
|
end
|
45
54
|
|
46
55
|
def finish
|
47
|
-
s = Array.new 25, 0
|
56
|
+
s = Array.new( 25, 0 )
|
48
57
|
width = 200 - @size * 2
|
58
|
+
|
59
|
+
### note: padding changed in final FIPS PUB 202 standard
|
60
|
+
## from "\x01" to "\x06"
|
49
61
|
padding = "\x01"
|
50
62
|
|
51
63
|
buffer = @buffer
|
52
64
|
buffer << padding << "\0" * (width - buffer.size % width)
|
53
65
|
buffer[-1] = (buffer[-1].ord | 0x80).chr
|
54
66
|
|
55
|
-
0.step buffer.size - 1, width do |j|
|
56
|
-
quads = buffer[j, width].unpack 'Q*'
|
67
|
+
0.step( buffer.size - 1, width ) do |j|
|
68
|
+
quads = buffer[j, width].unpack( 'Q*' )
|
57
69
|
(width / 8).times do |i|
|
58
70
|
s[i] ^= quads[i]
|
59
71
|
end
|
60
72
|
|
61
|
-
|
73
|
+
_keccak( s )
|
62
74
|
end
|
63
75
|
|
64
76
|
s.pack('Q*')[0, @size]
|
65
77
|
end
|
66
78
|
|
67
79
|
private
|
68
|
-
def
|
69
|
-
24.times.each_with_object [] do |round, a|
|
80
|
+
def _keccak( s )
|
81
|
+
24.times.each_with_object( [] ) do |round, a|
|
70
82
|
# Theta
|
71
83
|
5.times do |i|
|
72
84
|
a[i] = s[i] ^ s[i + 5] ^ s[i + 10] ^ s[i + 15] ^ s[i + 20]
|
73
85
|
end
|
74
86
|
|
75
87
|
5.times do |i|
|
76
|
-
t = a[(i + 4) % 5] ^
|
77
|
-
0.step 24, 5 do |j|
|
88
|
+
t = a[(i + 4) % 5] ^ _rotate(a[(i + 1) % 5], 1)
|
89
|
+
0.step( 24, 5 ) do |j|
|
78
90
|
s[j + i] ^= t
|
79
91
|
end
|
80
92
|
end
|
@@ -84,12 +96,12 @@ module Digest
|
|
84
96
|
24.times do |i|
|
85
97
|
j = PILN[i]
|
86
98
|
a[0] = s[j]
|
87
|
-
s[j] =
|
99
|
+
s[j] = _rotate( t, ROTC[i] )
|
88
100
|
t = a[0]
|
89
101
|
end
|
90
102
|
|
91
103
|
# Chi
|
92
|
-
0.step 24, 5 do |j|
|
104
|
+
0.step( 24, 5 ) do |j|
|
93
105
|
5.times do |i|
|
94
106
|
a[i] = s[j + i]
|
95
107
|
end
|
@@ -104,8 +116,10 @@ module Digest
|
|
104
116
|
end
|
105
117
|
end
|
106
118
|
|
107
|
-
def
|
119
|
+
def _rotate( x, y )
|
108
120
|
(x << y | x >> 64 - y) & (1 << 64) - 1
|
109
121
|
end
|
110
|
-
|
111
|
-
|
122
|
+
|
123
|
+
|
124
|
+
end # class KeccakLite
|
125
|
+
end # module Digest
|
data/lib/digest/sha3.rb
CHANGED
@@ -6,8 +6,13 @@
|
|
6
6
|
|
7
7
|
## require 'digest'
|
8
8
|
|
9
|
+
##
|
10
|
+
# note: use SHA3Lite (or SHA3Zero? ZeroSHA3?) instead of SHA3
|
11
|
+
# to allow usage of native w/ c-extension SHA3 and "lite" version
|
12
|
+
|
13
|
+
|
9
14
|
module Digest
|
10
|
-
class
|
15
|
+
class SHA3Lite < Digest::Class
|
11
16
|
PILN = [10, 7, 11, 17, 18, 3, 5, 16,
|
12
17
|
8, 21, 24, 4, 15, 23, 19, 13,
|
13
18
|
12, 2, 20, 14, 22, 9, 6, 1]
|
@@ -25,16 +30,16 @@ module Digest
|
|
25
30
|
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
26
31
|
0x8000000000008080, 0x0000000080000001, 0x8000000080008008]
|
27
32
|
|
28
|
-
def initialize hash_size = 512
|
29
|
-
@size
|
30
|
-
@buffer = ''
|
33
|
+
def initialize( hash_size = 512 )
|
34
|
+
@size = hash_size / 8
|
35
|
+
@buffer = '' ## todo/check: make sure buffer is with encoding BINARY - why? why not?
|
31
36
|
end
|
32
37
|
|
33
|
-
def << s
|
38
|
+
def <<( s )
|
34
39
|
@buffer << s
|
35
40
|
self
|
36
41
|
end
|
37
|
-
|
42
|
+
alias_method :update, :<<
|
38
43
|
|
39
44
|
def reset
|
40
45
|
@buffer.clear
|
@@ -42,36 +47,40 @@ module Digest
|
|
42
47
|
end
|
43
48
|
|
44
49
|
def finish
|
45
|
-
s = Array.new 25, 0
|
50
|
+
s = Array.new( 25, 0 )
|
46
51
|
width = 200 - @size * 2
|
47
52
|
|
53
|
+
### note: padding changed in final FIPS PUB 202 standard
|
54
|
+
## from "\x01" to "\x06"
|
55
|
+
padding = "\x06"
|
56
|
+
|
48
57
|
buffer = @buffer
|
49
|
-
buffer <<
|
58
|
+
buffer << padding << "\0" * (width - buffer.size % width)
|
50
59
|
buffer[-1] = (buffer[-1].ord | 0x80).chr
|
51
60
|
|
52
|
-
0.step buffer.size - 1, width do |j|
|
53
|
-
quads = buffer[j, width].unpack 'Q*'
|
61
|
+
0.step( buffer.size - 1, width ) do |j|
|
62
|
+
quads = buffer[j, width].unpack( 'Q*' )
|
54
63
|
(width / 8).times do |i|
|
55
64
|
s[i] ^= quads[i]
|
56
65
|
end
|
57
66
|
|
58
|
-
|
67
|
+
_keccak( s )
|
59
68
|
end
|
60
69
|
|
61
70
|
s.pack('Q*')[0, @size]
|
62
71
|
end
|
63
72
|
|
64
|
-
|
65
|
-
def
|
66
|
-
24.times.each_with_object [] do |round, a|
|
73
|
+
private
|
74
|
+
def _keccak( s )
|
75
|
+
24.times.each_with_object( [] ) do |round, a|
|
67
76
|
# Theta
|
68
77
|
5.times do |i|
|
69
78
|
a[i] = s[i] ^ s[i + 5] ^ s[i + 10] ^ s[i + 15] ^ s[i + 20]
|
70
79
|
end
|
71
80
|
|
72
81
|
5.times do |i|
|
73
|
-
t = a[(i + 4) % 5] ^
|
74
|
-
0.step 24, 5 do |j|
|
82
|
+
t = a[(i + 4) % 5] ^ _rotate(a[(i + 1) % 5], 1)
|
83
|
+
0.step( 24, 5 ) do |j|
|
75
84
|
s[j + i] ^= t
|
76
85
|
end
|
77
86
|
end
|
@@ -81,12 +90,12 @@ module Digest
|
|
81
90
|
24.times do |i|
|
82
91
|
j = PILN[i]
|
83
92
|
a[0] = s[j]
|
84
|
-
s[j] =
|
93
|
+
s[j] = _rotate( t, ROTC[i] )
|
85
94
|
t = a[0]
|
86
95
|
end
|
87
96
|
|
88
97
|
# Chi
|
89
|
-
0.step 24, 5 do |j|
|
98
|
+
0.step( 24, 5 ) do |j|
|
90
99
|
5.times do |i|
|
91
100
|
a[i] = s[j + i]
|
92
101
|
end
|
@@ -101,8 +110,9 @@ module Digest
|
|
101
110
|
end
|
102
111
|
end
|
103
112
|
|
104
|
-
def
|
113
|
+
def _rotate( x, y )
|
105
114
|
(x << y | x >> 64 - y) & (1 << 64) - 1
|
106
115
|
end
|
107
|
-
|
108
|
-
end
|
116
|
+
|
117
|
+
end # class SHA3Lite
|
118
|
+
end # module Digest
|
data/lib/ethlite/abi/type.rb
CHANGED
@@ -2,17 +2,16 @@ module Ethlite
|
|
2
2
|
module Abi
|
3
3
|
class Type
|
4
4
|
|
5
|
-
class ParseError < StandardError;
|
6
|
-
|
5
|
+
class ParseError < StandardError; end
|
6
|
+
|
7
7
|
|
8
|
-
class <<self
|
9
8
|
##
|
10
9
|
# Crazy regexp to seperate out base type component (eg. uint), size (eg.
|
11
10
|
# 256, 128x128, nil), array component (eg. [], [45], nil)
|
12
11
|
#
|
13
|
-
def parse(type)
|
12
|
+
def self.parse( type )
|
14
13
|
|
15
|
-
return parse('uint256')
|
14
|
+
return parse('uint256') if type=='trcToken'
|
16
15
|
|
17
16
|
if type =~ /^\((.*)\)((\[[0-9]*\])*)/
|
18
17
|
return Tuple.parse $1, $2.scan(/\[[0-9]*\]/)
|
@@ -56,10 +55,10 @@ module Ethlite
|
|
56
55
|
new(base, sub, dims.map {|x| x[1...-1].to_i})
|
57
56
|
end
|
58
57
|
|
59
|
-
def size_type
|
58
|
+
def self.size_type
|
60
59
|
@size_type ||= new('uint', 256, [])
|
61
60
|
end
|
62
|
-
|
61
|
+
|
63
62
|
|
64
63
|
attr :base, :sub, :dims
|
65
64
|
|
@@ -69,7 +68,7 @@ module Ethlite
|
|
69
68
|
# @param dims [Array[Integer]] dimensions of array type, e.g. [1,2,0]
|
70
69
|
# for uint256[1][2][], [] for non-array type
|
71
70
|
#
|
72
|
-
def initialize(base, sub, dims)
|
71
|
+
def initialize( base, sub, dims )
|
73
72
|
@base = base
|
74
73
|
@sub = sub
|
75
74
|
@dims = dims
|
@@ -123,7 +122,7 @@ module Ethlite
|
|
123
122
|
|
124
123
|
class Tuple < Type
|
125
124
|
|
126
|
-
def self.parse types, dims
|
125
|
+
def self.parse( types, dims )
|
127
126
|
|
128
127
|
depth = 0
|
129
128
|
collected = []
|
@@ -156,7 +155,8 @@ module Ethlite
|
|
156
155
|
end
|
157
156
|
|
158
157
|
attr_reader :types, :parsed_types
|
159
|
-
|
158
|
+
|
159
|
+
def initialize( types, dims )
|
160
160
|
super('tuple', '', dims)
|
161
161
|
@types = types
|
162
162
|
@parsed_types = types.map{|t| Type.parse t}
|
@@ -188,14 +188,11 @@ module Ethlite
|
|
188
188
|
subtype.dynamic? ? nil : dims.last * subtype.size
|
189
189
|
end
|
190
190
|
end
|
191
|
-
|
192
|
-
|
193
191
|
end
|
194
192
|
|
195
193
|
def subtype
|
196
194
|
@subtype ||= Tuple.new(types, dims[0...-1])
|
197
195
|
end
|
198
|
-
|
199
196
|
end
|
200
197
|
|
201
198
|
|
data/lib/ethlite/abi/utils.rb
CHANGED
@@ -12,16 +12,16 @@ module Abi
|
|
12
12
|
def keccak256(x)
|
13
13
|
# Digest::SHA3.new(256).digest(x)
|
14
14
|
## Digest::Keccak.digest(x, 256)
|
15
|
-
Digest::
|
15
|
+
Digest::KeccakLite.new(256).digest( x )
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
## check where required / in use - what for?
|
18
|
+
## todo/check where required / in use - what for?
|
20
19
|
def keccak512(x)
|
21
20
|
# Digest::SHA3.new(512).digest(x)
|
22
|
-
Digest::Keccak.digest(x, 512)
|
21
|
+
# Digest::Keccak.digest(x, 512)
|
22
|
+
Digest::KeccakLite.new(512).digest( x )
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
|
26
26
|
def keccak256_rlp(x)
|
27
27
|
keccak256 RLP.encode(x)
|
@@ -56,44 +56,50 @@ module Abi
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def to_signed(i)
|
59
|
-
i >
|
59
|
+
i > INT_MAX ? (i-TT256) : i
|
60
60
|
end
|
61
61
|
|
62
|
-
def base58_check_to_bytes(s)
|
63
|
-
leadingzbytes = s.match(/\A1*/)[0]
|
64
|
-
data = Constant::BYTE_ZERO * leadingzbytes.size + BaseConvert.convert(s, 58, 256)
|
65
|
-
|
66
|
-
raise ChecksumError, "double sha256 checksum doesn't match" unless double_sha256(data[0...-4])[0,4] == data[-4..-1]
|
67
|
-
data[1...-4]
|
68
|
-
end
|
69
|
-
|
70
|
-
def bytes_to_base58_check(bytes, magicbyte=0)
|
71
|
-
bs = "#{magicbyte.chr}#{bytes}"
|
72
|
-
leadingzbytes = bs.match(/\A#{Constant::BYTE_ZERO}*/)[0]
|
73
|
-
checksum = double_sha256(bs)[0,4]
|
74
|
-
'1'*leadingzbytes.size + BaseConvert.convert("#{bs}#{checksum}", 256, 58)
|
75
|
-
end
|
76
62
|
|
77
63
|
def ceil32(x)
|
78
64
|
x % 32 == 0 ? x : (x + 32 - x%32)
|
79
65
|
end
|
80
66
|
|
81
67
|
def encode_hex(b)
|
82
|
-
|
68
|
+
raise TypeError, "Value must be an instance of String" unless b.instance_of?(String)
|
69
|
+
b.unpack("H*").first
|
83
70
|
end
|
84
71
|
|
85
|
-
def decode_hex(
|
86
|
-
|
72
|
+
def decode_hex(str)
|
73
|
+
raise TypeError, "Value must be an instance of string" unless sstr.instance_of?(String)
|
74
|
+
raise TypeError, 'Non-hexadecimal digit found' unless str =~ /\A[0-9a-fA-F]*\z/
|
75
|
+
[str].pack("H*")
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
def int_to_big_endian(n)
|
82
|
+
RLP::Sedes.big_endian_int.serialize n
|
87
83
|
end
|
88
84
|
|
89
85
|
def big_endian_to_int(s)
|
90
86
|
RLP::Sedes.big_endian_int.deserialize s.sub(/\A(\x00)+/, '')
|
91
87
|
end
|
92
88
|
|
93
|
-
|
94
|
-
|
89
|
+
|
90
|
+
def encode_int(n)
|
91
|
+
raise ArgumentError, "Integer invalid or out of range: #{n}" unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
92
|
+
int_to_big_endian n
|
95
93
|
end
|
96
94
|
|
95
|
+
def decode_int(v)
|
96
|
+
raise ArgumentError, "No leading zero bytes allowed for integers" if v.size > 0 && (v[0] == BYTE_ZERO || v[0] == 0)
|
97
|
+
big_endian_to_int v
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
97
103
|
def lpad(x, symbol, l)
|
98
104
|
return x if x.size >= l
|
99
105
|
symbol * (l - x.size) + x
|
@@ -124,15 +130,6 @@ module Abi
|
|
124
130
|
zpad_int x, 20
|
125
131
|
end
|
126
132
|
|
127
|
-
def encode_int(n)
|
128
|
-
raise ArgumentError, "Integer invalid or out of range: #{n}" unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
129
|
-
int_to_big_endian n
|
130
|
-
end
|
131
|
-
|
132
|
-
def decode_int(v)
|
133
|
-
raise ArgumentError, "No leading zero bytes allowed for integers" if v.size > 0 && (v[0] == Constant::BYTE_ZERO || v[0] == 0)
|
134
|
-
big_endian_to_int v
|
135
|
-
end
|
136
133
|
|
137
134
|
def bytearray_to_int(arr)
|
138
135
|
o = 0
|
@@ -148,6 +145,7 @@ module Abi
|
|
148
145
|
bytes.unpack('C*')
|
149
146
|
end
|
150
147
|
|
148
|
+
|
151
149
|
def coerce_to_int(x)
|
152
150
|
if x.is_a?(Numeric)
|
153
151
|
x
|
@@ -178,19 +176,6 @@ module Abi
|
|
178
176
|
end
|
179
177
|
end
|
180
178
|
|
181
|
-
def normalize_address(x, allow_blank: false)
|
182
|
-
address = Address.new(x)
|
183
|
-
raise ValueError, "address is blank" if !allow_blank && address.blank?
|
184
|
-
address.to_bytes
|
185
|
-
end
|
186
|
-
|
187
|
-
def mk_contract_address(sender, nonce)
|
188
|
-
keccak256_rlp([normalize_address(sender), nonce])[12..-1]
|
189
|
-
end
|
190
|
-
|
191
|
-
def mk_metropolis_contract_address(sender, initcode)
|
192
|
-
keccak256(normalize_address(sender) + initcode)[12..-1]
|
193
|
-
end
|
194
179
|
|
195
180
|
|
196
181
|
def parse_int_or_hex(s)
|
@@ -203,6 +188,24 @@ module Abi
|
|
203
188
|
end
|
204
189
|
end
|
205
190
|
|
191
|
+
|
192
|
+
=begin
|
193
|
+
## add? moved over from the old module Utility
|
194
|
+
def hex( num )
|
195
|
+
'0x' + num.to_s(16)
|
196
|
+
end
|
197
|
+
|
198
|
+
def from_hex( h )
|
199
|
+
h.nil? ? 0 : (h.kind_of?(String) ? h.to_i(16) : h)
|
200
|
+
end
|
201
|
+
=end
|
202
|
+
|
203
|
+
|
204
|
+
def remove_0x_head( s )
|
205
|
+
return s if !s || s.length<2
|
206
|
+
s[0,2] == '0x' ? s[2..-1] : s
|
207
|
+
end
|
208
|
+
|
206
209
|
def normalize_hex_without_prefix(s)
|
207
210
|
if s[0,2] == '0x'
|
208
211
|
(s.size % 2 == 1 ? '0' : '') + s[2..-1]
|
@@ -211,6 +214,7 @@ module Abi
|
|
211
214
|
end
|
212
215
|
end
|
213
216
|
|
217
|
+
|
214
218
|
def function_signature method_name, arg_types
|
215
219
|
"#{method_name}(#{arg_types.join(',')})"
|
216
220
|
end
|
@@ -218,8 +222,6 @@ module Abi
|
|
218
222
|
def signature_hash signature, length=64
|
219
223
|
encode_hex(keccak256(signature))[0...length]
|
220
224
|
end
|
221
|
-
|
222
|
-
|
223
225
|
end
|
224
226
|
|
225
227
|
end # module Abi
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
module Ethlite
|
3
|
+
module Constant
|
4
|
+
|
5
|
+
|
6
|
+
## todo/check - use encoding -ascii-8bit for source file or ? - why? why not?
|
7
|
+
## use #b/.b to ensure binary encoding? - why? why not?
|
8
|
+
|
9
|
+
## todo/check: use auto-freeze string literals magic comment - why? why not?
|
10
|
+
BYTE_EMPTY = "".b.freeze
|
11
|
+
BYTE_ZERO = "\x00".b.freeze
|
12
|
+
BYTE_ONE = "\x01".b.freeze
|
13
|
+
|
14
|
+
|
15
|
+
TT32 = 2**32
|
16
|
+
TT40 = 2**40
|
17
|
+
TT160 = 2**160
|
18
|
+
TT256 = 2**256
|
19
|
+
TT64M1 = 2**64 - 1
|
20
|
+
|
21
|
+
UINT_MAX = 2**256 - 1
|
22
|
+
UINT_MIN = 0
|
23
|
+
INT_MAX = 2**255 - 1
|
24
|
+
INT_MIN = -2**255
|
25
|
+
|
26
|
+
HASH_ZERO = ("\x00"*32).b.freeze
|
27
|
+
|
28
|
+
|
29
|
+
PUBKEY_ZERO = ("\x00"*32).b.freeze
|
30
|
+
PRIVKEY_ZERO = ("\x00"*32).b.freeze
|
31
|
+
|
32
|
+
PRIVKEY_ZERO_HEX = ('0'*64).freeze
|
33
|
+
|
34
|
+
CONTRACT_CODE_SIZE_LIMIT = 0x6000
|
35
|
+
|
36
|
+
|
37
|
+
end # module Constant
|
38
|
+
end # module Ethlite
|
data/lib/ethlite/contract.rb
CHANGED
@@ -1,38 +1,54 @@
|
|
1
1
|
module Ethlite
|
2
2
|
class ContractMethod
|
3
|
-
include Utility
|
4
3
|
|
5
|
-
|
6
|
-
|
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
|
+
type = abi['type'] || 'function'
|
13
|
+
|
14
|
+
new( name, inputs: input_types,
|
15
|
+
outputs: output_types,
|
16
|
+
constant: constant,
|
17
|
+
type: type )
|
18
|
+
end
|
19
|
+
|
20
|
+
def self._parse_component_type( argument )
|
21
|
+
if argument['type'] =~ /^tuple((\[[0-9]*\])*)/
|
22
|
+
argument['components'] ? "(#{argument['components'].collect{ |c| _parse_component_type( c ) }.join(',')})#{$1}"
|
23
|
+
: "()#{$1}"
|
24
|
+
else
|
25
|
+
argument['type']
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
attr_reader :signature,
|
7
33
|
:name,
|
8
34
|
:signature_hash,
|
9
35
|
:input_types,
|
10
36
|
:output_types,
|
11
37
|
:constant
|
12
38
|
|
13
|
-
def initialize(
|
14
|
-
|
15
|
-
|
39
|
+
def initialize( name, inputs:,
|
40
|
+
outputs: [],
|
41
|
+
constant: true,
|
42
|
+
type: 'function' )
|
43
|
+
@name = name
|
44
|
+
@constant = constant
|
45
|
+
@input_types = inputs
|
46
|
+
@output_types = outputs
|
16
47
|
|
17
|
-
@abi = abi
|
18
|
-
@name = abi['name']
|
19
|
-
@constant = !!abi['constant'] || abi['stateMutability']=='view'
|
20
|
-
@input_types = abi['inputs'] ? abi['inputs'].map{|a| parse_component_type a } : []
|
21
|
-
@output_types = abi['outputs'] ? abi['outputs'].map{|a| parse_component_type a } : nil
|
22
48
|
@signature = Abi::Utils.function_signature( @name, @input_types )
|
23
|
-
@signature_hash = Abi::Utils.signature_hash( @signature,
|
49
|
+
@signature_hash = Abi::Utils.signature_hash( @signature, type=='event' ? 64 : 8)
|
24
50
|
end
|
25
51
|
|
26
|
-
def parse_component_type( argument )
|
27
|
-
if argument['type'] =~ /^tuple((\[[0-9]*\])*)/
|
28
|
-
argument['components'] ? "(#{argument['components'].collect{|c| parse_component_type( c ) }.join(',')})#{$1}"
|
29
|
-
: "()#{$1}"
|
30
|
-
else
|
31
|
-
argument['type']
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
52
|
def do_call( rpc, contract_address, args )
|
37
53
|
data = '0x' + @signature_hash + Abi::Utils.encode_hex(
|
38
54
|
Abi::AbiCoder.encode_abi(@input_types, args) )
|
@@ -47,7 +63,7 @@
|
|
47
63
|
puts "response:"
|
48
64
|
pp response
|
49
65
|
|
50
|
-
string_data = [remove_0x_head(response)].pack('H*')
|
66
|
+
string_data = [Abi::Utils.remove_0x_head(response)].pack('H*')
|
51
67
|
return nil if string_data.empty?
|
52
68
|
|
53
69
|
result = Abi::AbiCoder.decode_abi( @output_types, string_data )
|
data/lib/ethlite/version.rb
CHANGED
data/lib/ethlite.rb
CHANGED
@@ -10,28 +10,27 @@ require 'openssl'
|
|
10
10
|
require 'digest'
|
11
11
|
|
12
12
|
## 3rd party gems
|
13
|
-
require 'rlp'
|
13
|
+
require 'rlp-lite'
|
14
14
|
|
15
15
|
## bundled require 'digest/keccak' ## gem keccak - see https://rubygems.org/gems/keccak
|
16
|
-
|
16
|
+
require_relative 'digest/keccak'
|
17
|
+
require_relative 'digest/sha3'
|
17
18
|
|
19
|
+
require_relative 'jsonrpc/jsonrpc'
|
18
20
|
|
19
21
|
|
20
22
|
|
21
23
|
## our own code
|
22
24
|
require_relative 'ethlite/version' # note: let version always go first
|
23
25
|
|
26
|
+
require_relative 'ethlite/constant'
|
27
|
+
|
24
28
|
|
25
29
|
require_relative 'ethlite/abi/type'
|
26
|
-
require_relative 'ethlite/abi/constant'
|
27
|
-
require_relative 'ethlite/abi/exceptions'
|
28
30
|
require_relative 'ethlite/abi/utils'
|
29
31
|
require_relative 'ethlite/abi/abi_coder'
|
30
32
|
|
31
33
|
|
32
|
-
require_relative 'ethlite/rpc'
|
33
|
-
|
34
|
-
require_relative 'ethlite/utility'
|
35
34
|
require_relative 'ethlite/contract'
|
36
35
|
|
37
36
|
|
@@ -39,8 +38,14 @@ require_relative 'ethlite/contract'
|
|
39
38
|
|
40
39
|
module Ethlite
|
41
40
|
class Configuration
|
42
|
-
def rpc() @rpc ||
|
43
|
-
def rpc=(value)
|
41
|
+
def rpc() @rpc || JsonRpc.new( ENV['INFURA_URI'] ); end
|
42
|
+
def rpc=(value)
|
43
|
+
@rpc = if value.is_a?( String )
|
44
|
+
JsonRpc.new( value ) ## auto-wrap in (built-in/simple) jsonrpc client/serverproxy
|
45
|
+
else
|
46
|
+
value
|
47
|
+
end
|
48
|
+
end
|
44
49
|
end # class Configuration
|
45
50
|
|
46
51
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
###
|
3
|
+
# simple JsonRpc client
|
4
|
+
#
|
5
|
+
# see https://www.jsonrpc.org/specification
|
6
|
+
# https://en.wikipedia.org/wiki/JSON-RPC
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
class JsonRpc
|
11
|
+
def initialize( uri )
|
12
|
+
@uri = uri ## assume uri always as string for now
|
13
|
+
@request_id = 1
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def request( method, params=[] )
|
18
|
+
|
19
|
+
data = { jsonrpc: '2.0',
|
20
|
+
method: method,
|
21
|
+
params: params,
|
22
|
+
id: @request_id }
|
23
|
+
|
24
|
+
@request_id += 1
|
25
|
+
|
26
|
+
puts "json POST payload:"
|
27
|
+
puts data.to_json
|
28
|
+
|
29
|
+
response = Webclient.post( @uri, json: data )
|
30
|
+
|
31
|
+
|
32
|
+
if response.status.nok?
|
33
|
+
raise "Error code #{response.status.code} on request #{@uri} #{data}"
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
body = JSON.parse( response.body, max_nesting: 1500 )
|
38
|
+
|
39
|
+
if body['result']
|
40
|
+
body['result']
|
41
|
+
elsif body['error']
|
42
|
+
raise "Error #{@uri} #{body['error']} on request #{@uri} #{data}"
|
43
|
+
else
|
44
|
+
raise "No response on request #{@uri} #{data}"
|
45
|
+
end
|
46
|
+
end # method request
|
47
|
+
end # class JsonRpc
|
48
|
+
|
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.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-19 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: rlp
|
28
|
+
name: rlp-lite
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -86,18 +86,16 @@ files:
|
|
86
86
|
- Manifest.txt
|
87
87
|
- README.md
|
88
88
|
- Rakefile
|
89
|
-
- lib/digest/
|
89
|
+
- lib/digest/keccak.rb
|
90
90
|
- lib/digest/sha3.rb
|
91
91
|
- lib/ethlite.rb
|
92
92
|
- lib/ethlite/abi/abi_coder.rb
|
93
|
-
- lib/ethlite/abi/constant.rb
|
94
|
-
- lib/ethlite/abi/exceptions.rb
|
95
93
|
- lib/ethlite/abi/type.rb
|
96
94
|
- lib/ethlite/abi/utils.rb
|
95
|
+
- lib/ethlite/constant.rb
|
97
96
|
- lib/ethlite/contract.rb
|
98
|
-
- lib/ethlite/rpc.rb
|
99
|
-
- lib/ethlite/utility.rb
|
100
97
|
- lib/ethlite/version.rb
|
98
|
+
- lib/jsonrpc/jsonrpc.rb
|
101
99
|
homepage: https://github.com/pixelartexchange/artbase
|
102
100
|
licenses:
|
103
101
|
- Public Domain
|
data/lib/ethlite/abi/constant.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
|
2
|
-
module Ethlite
|
3
|
-
module Abi
|
4
|
-
module Constant
|
5
|
-
|
6
|
-
BYTE_EMPTY = "".freeze
|
7
|
-
BYTE_ZERO = "\x00".freeze
|
8
|
-
BYTE_ONE = "\x01".freeze
|
9
|
-
|
10
|
-
TT32 = 2**32
|
11
|
-
TT40 = 2**40
|
12
|
-
TT160 = 2**160
|
13
|
-
TT256 = 2**256
|
14
|
-
TT64M1 = 2**64 - 1
|
15
|
-
|
16
|
-
UINT_MAX = 2**256 - 1
|
17
|
-
UINT_MIN = 0
|
18
|
-
INT_MAX = 2**255 - 1
|
19
|
-
INT_MIN = -2**255
|
20
|
-
|
21
|
-
HASH_ZERO = ("\x00"*32).freeze
|
22
|
-
|
23
|
-
PUBKEY_ZERO = ("\x00"*32).freeze
|
24
|
-
PRIVKEY_ZERO = ("\x00"*32).freeze
|
25
|
-
PRIVKEY_ZERO_HEX = ('0'*64).freeze
|
26
|
-
|
27
|
-
CONTRACT_CODE_SIZE_LIMIT = 0x6000
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
end # module Abi
|
32
|
-
end # module Ethlite
|
@@ -1,29 +0,0 @@
|
|
1
|
-
|
2
|
-
module Ethlite
|
3
|
-
module Abi
|
4
|
-
|
5
|
-
class DeprecatedError < StandardError; end
|
6
|
-
class ChecksumError < StandardError; end
|
7
|
-
class FormatError < StandardError; end
|
8
|
-
class ValidationError < StandardError; end
|
9
|
-
class ValueError < StandardError; end
|
10
|
-
class AssertError < StandardError; end
|
11
|
-
|
12
|
-
class UnknownParentError < StandardError; end
|
13
|
-
class InvalidBlock < ValidationError; end
|
14
|
-
class InvalidUncles < ValidationError; end
|
15
|
-
|
16
|
-
class InvalidTransaction < ValidationError; end
|
17
|
-
class UnsignedTransactionError < InvalidTransaction; end
|
18
|
-
class InvalidNonce < InvalidTransaction; end
|
19
|
-
class InsufficientStartGas < InvalidTransaction; end
|
20
|
-
class InsufficientBalance < InvalidTransaction; end
|
21
|
-
class BlockGasLimitReached < InvalidTransaction; end
|
22
|
-
|
23
|
-
class InvalidSPVProof < ValidationError; end
|
24
|
-
|
25
|
-
class ContractCreationFailed < StandardError; end
|
26
|
-
class TransactionFailed < StandardError; end
|
27
|
-
|
28
|
-
end # module Abi
|
29
|
-
end # module Ethlite
|
data/lib/ethlite/rpc.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
module Ethlite
|
2
|
-
|
3
|
-
class Rpc
|
4
|
-
def initialize( uri )
|
5
|
-
@client_id = Random.rand( 10000000 )
|
6
|
-
|
7
|
-
@uri = URI.parse( uri )
|
8
|
-
end
|
9
|
-
|
10
|
-
def request( method, params=[] )
|
11
|
-
opts = {}
|
12
|
-
if @uri.instance_of?( URI::HTTPS )
|
13
|
-
opts[:use_ssl] = true
|
14
|
-
opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
|
15
|
-
end
|
16
|
-
|
17
|
-
Net::HTTP.start( @uri.host, @uri.port, **opts ) do |http|
|
18
|
-
headers = {"Content-Type" => "application/json"}
|
19
|
-
request = Net::HTTP::Post.new( @uri.request_uri, headers )
|
20
|
-
|
21
|
-
json = { jsonrpc: '2.0',
|
22
|
-
method: method,
|
23
|
-
params: params,
|
24
|
-
id: @client_id }.to_json
|
25
|
-
|
26
|
-
puts "json POST payload:"
|
27
|
-
puts json
|
28
|
-
|
29
|
-
request.body = json
|
30
|
-
response = http.request( request )
|
31
|
-
|
32
|
-
raise "Error code #{response.code} on request #{@uri.to_s} #{request.body}" unless response.kind_of?( Net::HTTPOK )
|
33
|
-
|
34
|
-
body = JSON.parse(response.body, max_nesting: 1500)
|
35
|
-
|
36
|
-
if body['result']
|
37
|
-
body['result']
|
38
|
-
elsif body['error']
|
39
|
-
raise "Error #{@uri.to_s} #{body['error']} on request #{@uri.to_s} #{request.body}"
|
40
|
-
else
|
41
|
-
raise "No response on request #{@uri.to_s} #{request.body}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end # class Rpc
|
46
|
-
|
47
|
-
end # module Ethlite
|
48
|
-
|
data/lib/ethlite/utility.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module Ethlite
|
2
|
-
|
3
|
-
module Utility
|
4
|
-
|
5
|
-
def hex( num )
|
6
|
-
'0x' + num.to_s(16)
|
7
|
-
end
|
8
|
-
|
9
|
-
def from_hex( h )
|
10
|
-
h.nil? ? 0 : (h.kind_of?(String) ? h.to_i(16) : h)
|
11
|
-
end
|
12
|
-
|
13
|
-
def remove_0x_head( s )
|
14
|
-
return s if !s || s.length<2
|
15
|
-
s[0,2] == '0x' ? s[2..-1] : s
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
def wei_to_ether( wei )
|
20
|
-
1.0 * wei / 10**18
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end # module Ethlite
|