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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdacaafee691ecb72746721479d637e03b211c4afbcde0c4c938edc50695ccf8
4
- data.tar.gz: 607cb3eda84667009ac105e998afb56a4af0dfa23dcc0a47264623e8e3409c21
3
+ metadata.gz: a6a9601ad8c91c592541ffc721dbe9bbb8572683ef88c995a1bb810f7da79e33
4
+ data.tar.gz: 4ddf8c5a91c9a370e580bc9519f4d7c9832f863f31e4dfb8fa2b0505c2c6d6e0
5
5
  SHA512:
6
- metadata.gz: 459910398810dfa9ff9dab030feb0a185a03afa5d440656cc37ef4479dd54f49e0cd16b9c7e018b72d3a9507c109deb01e234f408e5b13131f14d044701868be
7
- data.tar.gz: 6783748547fa38964c62f695df60d4d5f8533fceb650c212e4ae0d6f20619cd9f42dea747f1a0c3bc28512b336998cde5c80fce78e4c3445a6e3723e05a5c54d
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/keccak256.rb
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
@@ -21,7 +21,7 @@ Hoe.spec 'ethlite' do
21
21
  self.extra_deps = [
22
22
  ['cocos'],
23
23
  ## ['keccak'], -- try using bundled ruby version for now
24
- ['rlp'],
24
+ ['rlp-lite'],
25
25
  ]
26
26
 
27
27
  self.licenses = ['Public Domain']
@@ -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 Keccak256 < Digest::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
- def initialize
31
- @size = 256 / 8
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
- alias update <<
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
- keccak s
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 keccak s
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] ^ rotate(a[(i + 1) % 5], 1)
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] = rotate t, ROTC[i]
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 rotate x, y
119
+ def _rotate( x, y )
108
120
  (x << y | x >> 64 - y) & (1 << 64) - 1
109
121
  end
110
- end
111
- end
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 SHA3 < Digest::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 = hash_size / 8
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
- alias update <<
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 << "\x06" << "\0" * (width - buffer.size % width)
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
- keccak s
67
+ _keccak( s )
59
68
  end
60
69
 
61
70
  s.pack('Q*')[0, @size]
62
71
  end
63
72
 
64
- private
65
- def keccak s
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] ^ rotate(a[(i + 1) % 5], 1)
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] = rotate t, ROTC[i]
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 rotate x, y
113
+ def _rotate( x, y )
105
114
  (x << y | x >> 64 - y) & (1 << 64) - 1
106
115
  end
107
- end
108
- end
116
+
117
+ end # class SHA3Lite
118
+ end # module Digest
@@ -14,8 +14,11 @@ module Ethlite
14
14
 
15
15
  include Constant
16
16
 
17
+
17
18
  class EncodingError < StandardError; end
18
19
  class DecodingError < StandardError; end
20
+ class ValueError < StandardError; end
21
+
19
22
  class ValueOutOfBounds < ValueError; end
20
23
 
21
24
  ##
@@ -2,17 +2,16 @@ module Ethlite
2
2
  module Abi
3
3
  class Type
4
4
 
5
- class ParseError < StandardError;
6
- end
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') if type=='trcToken'
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
- end
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
- def initialize types, dims
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
 
@@ -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::Keccak256.digest( x )
15
+ Digest::KeccakLite.new(256).digest( x )
16
16
  end
17
17
 
18
- =begin
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
- =end
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 > Constant::INT_MAX ? (i-Constant::TT256) : 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
- RLP::Utils.encode_hex b
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(s)
86
- RLP::Utils.decode_hex s
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
- def int_to_big_endian(n)
94
- RLP::Sedes.big_endian_int.serialize n
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
@@ -1,38 +1,54 @@
1
1
  module Ethlite
2
2
  class ContractMethod
3
- include Utility
4
3
 
5
- attr_reader :abi,
6
- :signature,
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( abi )
14
- ## convenience helper - auto-convert to json if string passed in
15
- abi = JSON.parse( abi ) if abi.is_a?( String )
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, abi['type']=='event' ? 64 : 8)
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 )
@@ -3,7 +3,7 @@
3
3
  module Ethlite
4
4
  MAJOR = 0
5
5
  MINOR = 2
6
- PATCH = 2
6
+ PATCH = 4
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
9
9
  def self.version
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' ## gem rlp - see https://rubygems.org/gems/rlp
13
+ require 'rlp-lite'
14
14
 
15
15
  ## bundled require 'digest/keccak' ## gem keccak - see https://rubygems.org/gems/keccak
16
- require 'digest/keccak256'
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 || Rpc.new( ENV['INFURA_URI'] ); end
43
- def rpc=(value) @rpc = value; end
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.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-14 00:00:00.000000000 Z
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/keccak256.rb
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
@@ -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
-
@@ -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