rubysol 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +13 -0
- data/README.md +170 -0
- data/Rakefile +33 -0
- data/lib/rubysol/abi_proxy.rb +206 -0
- data/lib/rubysol/contract/crypto.rb +27 -0
- data/lib/rubysol/contract/runtime.rb +56 -0
- data/lib/rubysol/contract.rb +400 -0
- data/lib/rubysol/generator.rb +394 -0
- data/lib/rubysol/library.rb +126 -0
- data/lib/rubysol/runtime.rb +82 -0
- data/lib/rubysol/version.rb +23 -0
- data/lib/rubysol.rb +117 -0
- metadata +138 -0
@@ -0,0 +1,394 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
##
|
4
|
+
# "centralize"
|
5
|
+
## meta-programming magic (code generation) in module here - why? why not?
|
6
|
+
## find a better name e.g Magic? Pilot? or CodeGen or Metagen or ???
|
7
|
+
module Generator
|
8
|
+
|
9
|
+
|
10
|
+
############
|
11
|
+
## helpers
|
12
|
+
def self._demodulize( path )
|
13
|
+
## turn class.name into a symbol cutting off all namepspaces (::)
|
14
|
+
## e.g. Contracts::ERC20 => ERC20
|
15
|
+
##
|
16
|
+
## note: ActiveSupport::String#demodulize is the same (for string)
|
17
|
+
|
18
|
+
path = path.to_s
|
19
|
+
if i = path.rindex('::')
|
20
|
+
path[(i+2)..-1]
|
21
|
+
else
|
22
|
+
path
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
module Function
|
29
|
+
####
|
30
|
+
## rename to pack_params/args or cook_params or typed_params or ???
|
31
|
+
|
32
|
+
|
33
|
+
def self.typecheck( type, value )
|
34
|
+
## check if value is already typed?
|
35
|
+
if value.is_a?( Types::Typed )
|
36
|
+
## type check
|
37
|
+
raise TypeError, "type #{type} expected; got #{value.pretty_print_inspect}" unless type == value.type
|
38
|
+
value
|
39
|
+
else
|
40
|
+
## assume "literal" value
|
41
|
+
type.new( value )
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def self.params( method, inputs, *args_unsafe, **kwargs_unsafe )
|
47
|
+
m = method
|
48
|
+
params = m.parameters
|
49
|
+
## puts "params for #{m} - #{m.owner}:"
|
50
|
+
## pp params
|
51
|
+
|
52
|
+
## e.g.
|
53
|
+
## [[:keyreq, :name],
|
54
|
+
## [:keyreq, :symbol],
|
55
|
+
## [:keyreq, :decimals],
|
56
|
+
## [:keyreq, :totalSupply]]
|
57
|
+
## get keys
|
58
|
+
keys = params.map { |param| param[1] }
|
59
|
+
## puts "keys:"
|
60
|
+
## pp keys
|
61
|
+
|
62
|
+
kwargs = if !args_unsafe.empty?
|
63
|
+
values = inputs.zip( args_unsafe ).map do |type, value|
|
64
|
+
typecheck( type, value )
|
65
|
+
end
|
66
|
+
## puts "args:"
|
67
|
+
## puts values.pretty_print_inspect
|
68
|
+
|
69
|
+
keys.zip( values ).map do |key,value|
|
70
|
+
[key,value]
|
71
|
+
end.to_h
|
72
|
+
elsif !kwargs_unsafe.empty?
|
73
|
+
types = keys.zip( inputs ).map do |key,type|
|
74
|
+
[key,type]
|
75
|
+
end.to_h
|
76
|
+
## puts "types:"
|
77
|
+
## pp types
|
78
|
+
kwargs_unsafe.map do |key,value|
|
79
|
+
type = types[key]
|
80
|
+
raise ArgumentError, "unknown kwarg #{key}; sorry" if type.nil?
|
81
|
+
[key, typecheck( type, value)]
|
82
|
+
end.to_h
|
83
|
+
else
|
84
|
+
## assume no args - e.g. construct - double check for empty input spec/def!!!
|
85
|
+
if inputs.empty?
|
86
|
+
{}
|
87
|
+
else
|
88
|
+
raise ArgumentError, "Array (args) or Hash (kwargs) required for func call; sorry"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
unless kwargs.empty?
|
93
|
+
puts "#{kwargs.size} kwarg(s):"
|
94
|
+
pp kwargs
|
95
|
+
end
|
96
|
+
|
97
|
+
kwargs
|
98
|
+
end
|
99
|
+
end # module Function
|
100
|
+
|
101
|
+
|
102
|
+
## to rename to generate_typed or generate_wrapped or ??
|
103
|
+
## typed_method??
|
104
|
+
def self.typed_function( contract_class, name, inputs: )
|
105
|
+
## note: must? find matching method in class
|
106
|
+
## todo/fix: use methods( false) if available (do NOT look-up in subclasses or such)
|
107
|
+
|
108
|
+
## note: make sure name and contract_name is always a symbol
|
109
|
+
name = name.to_sym
|
110
|
+
contract_name = _demodulize( contract_class.name ).to_sym
|
111
|
+
|
112
|
+
exists = contract_class.instance_methods( false ).include?( name )
|
113
|
+
if !exists
|
114
|
+
error_message = "[ERRRO] no method #{name} found for sig in class #{contract_class.name}"
|
115
|
+
puts error_message
|
116
|
+
## fix: change to NoMethodError - exists?
|
117
|
+
raise NameError, error_message
|
118
|
+
end
|
119
|
+
|
120
|
+
## note: method lookup via method needs an object / INSTANCE
|
121
|
+
## NOT working with class only!!!!
|
122
|
+
## m = contract_class.method( name )
|
123
|
+
## puts " bingo! #{name} - #{m.owner}"
|
124
|
+
puts " bingo! #{name}"
|
125
|
+
|
126
|
+
|
127
|
+
## avoid recursive circle
|
128
|
+
## exlcude method from method_add automagic wrapping/generation
|
129
|
+
|
130
|
+
contract_class.sigs_exclude << :"__#{contract_name}__#{name}_unsafe"
|
131
|
+
contract_class.sigs_exclude << :"__#{contract_name}__#{name}"
|
132
|
+
contract_class.sigs_exclude << name
|
133
|
+
|
134
|
+
|
135
|
+
##
|
136
|
+
## use :name_raw instead of :name_unsafe - why? why not?
|
137
|
+
|
138
|
+
## rewire
|
139
|
+
## alias_method :name_unsafe, :name
|
140
|
+
## alias_method :name, :name_typed
|
141
|
+
contract_class.class_eval do
|
142
|
+
|
143
|
+
define_method :"__#{contract_name}__#{name}" do |*args_unsafe,**kwargs_unsafe|
|
144
|
+
puts "==> calling __#{contract_name}__#{name} (class #{contract_class.name})"
|
145
|
+
|
146
|
+
m = method( :"__#{contract_name}__#{name}_unsafe" )
|
147
|
+
kwargs = Function.params( m, inputs, *args_unsafe, **kwargs_unsafe )
|
148
|
+
|
149
|
+
ret = m.call( **kwargs )
|
150
|
+
## todo/fix:
|
151
|
+
## check returns type / value too
|
152
|
+
ret
|
153
|
+
end
|
154
|
+
|
155
|
+
## note: must add class/contract name (via prefix) here!!
|
156
|
+
## rename (unsafe/untyped) method
|
157
|
+
alias_method :"__#{contract_name}__#{name}_unsafe", name
|
158
|
+
alias_method name, :"__#{contract_name}__#{name}"
|
159
|
+
## if name == :constructor ### add ERC20() or such
|
160
|
+
## alias_method contract_name, :"__#{contract_name}__#{name}"
|
161
|
+
## end
|
162
|
+
## - use leading underscore - why? why not? e.g. _ERC20()
|
163
|
+
## as alternative to NOT conflict with global conversion function - why? why not?
|
164
|
+
end
|
165
|
+
end # method typed_function
|
166
|
+
|
167
|
+
|
168
|
+
def self.typed_library_function( contract_class, name, inputs: )
|
169
|
+
## note: must? find matching method in class
|
170
|
+
## todo/fix: use methods( false) if available (do NOT look-up in subclasses or such)
|
171
|
+
|
172
|
+
## todo - make sure contract_class is a module (not a class) !!!!
|
173
|
+
|
174
|
+
## note: make sure name and contract_name is always a symbol
|
175
|
+
name = name.to_sym
|
176
|
+
contract_name = _demodulize( contract_class.name ).to_sym
|
177
|
+
|
178
|
+
exists = contract_class.instance_methods( false ).include?( name )
|
179
|
+
if !exists
|
180
|
+
error_message = "[ERRRO] no method #{name} found for sig in module #{contract_class.name}"
|
181
|
+
puts error_message
|
182
|
+
## fix: change to NoMethodError - exists?
|
183
|
+
raise NameError, error_message
|
184
|
+
end
|
185
|
+
|
186
|
+
## note: method lookup via method needs an object / INSTANCE
|
187
|
+
## NOT working with class only!!!!
|
188
|
+
## m = contract_class.method( name )
|
189
|
+
## puts " bingo! #{name} - #{m.owner}"
|
190
|
+
puts " bingo! #{name}"
|
191
|
+
|
192
|
+
|
193
|
+
## avoid recursive circle
|
194
|
+
## exlcude method from method_add automagic wrapping/generation
|
195
|
+
|
196
|
+
contract_class.sigs_exclude << :"#{name}_unsafe"
|
197
|
+
contract_class.sigs_exclude << name
|
198
|
+
|
199
|
+
##
|
200
|
+
## use :name_raw instead of :name_unsafe - why? why not?
|
201
|
+
|
202
|
+
## rewire
|
203
|
+
## alias_method :name_unsafe, :name
|
204
|
+
## alias_method :name, :name_typed
|
205
|
+
contract_class.class_eval do
|
206
|
+
|
207
|
+
alias_method :"#{name}_unsafe", name
|
208
|
+
|
209
|
+
define_method name do |*args_unsafe,**kwargs_unsafe|
|
210
|
+
puts "==> calling #{contract_name}.#{name} (module #{contract_class.name})"
|
211
|
+
|
212
|
+
m = method( :"#{name}_unsafe" )
|
213
|
+
kwargs = Function.params( m, inputs, *args_unsafe, **kwargs_unsafe )
|
214
|
+
|
215
|
+
ret = m.call( **kwargs )
|
216
|
+
## todo/fix:
|
217
|
+
## check returns type / value too
|
218
|
+
ret
|
219
|
+
end
|
220
|
+
|
221
|
+
## make into module functions!!!
|
222
|
+
module_function name
|
223
|
+
module_function :"#{name}_unsafe"
|
224
|
+
end
|
225
|
+
end # method typed_library_function
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
###
|
230
|
+
# add public getters helpers
|
231
|
+
def self.getter_function( contract_class, name, type )
|
232
|
+
## note: make sure name is always a symbol
|
233
|
+
name = name.to_sym
|
234
|
+
|
235
|
+
if type.mapping?
|
236
|
+
mapping_getter_function( contract_class, name, type )
|
237
|
+
elsif type.array?
|
238
|
+
puts "[debug] auto-generate public array getter - #{name} : #{type}:"
|
239
|
+
|
240
|
+
|
241
|
+
## auto-add/register sig(nature) in here - why? why not?
|
242
|
+
## contract_class.sig( name,
|
243
|
+
## [Types::Typed::UIntType.instance],
|
244
|
+
## :view, returns: type.sub_type )
|
245
|
+
|
246
|
+
## auto-add/register sig(nature) in here - why? why not?
|
247
|
+
## fix-fix-fix - check if outputs is an array (or still single type?)
|
248
|
+
contract_class.sigs[ name ] = { inputs: [typeof(Types::UInt)],
|
249
|
+
outputs: [typeof(type.sub_type)],
|
250
|
+
options: [:view,:public] }
|
251
|
+
contract_class.sigs_exclude << name
|
252
|
+
|
253
|
+
|
254
|
+
contract_class.class_eval do
|
255
|
+
## note: hack: must use kwargs for now!!! index: (not index) for now
|
256
|
+
define_method name do |index:|
|
257
|
+
puts "[debug] call public (state) array getter for #{name} : #{type} with index #{index} (#{contract_class.name})"
|
258
|
+
puts "[debug] self -> #{self}"
|
259
|
+
value = instance_variable_get( :"@#{name}" )
|
260
|
+
value[index]
|
261
|
+
end
|
262
|
+
end # class_evel
|
263
|
+
|
264
|
+
## auto-add typed wrapper!!!!!
|
265
|
+
typed_function( contract_class, name, inputs: [typeof(Types::UInt)] )
|
266
|
+
else
|
267
|
+
puts "[debug] auto-generate public getter - #{name} : #{type}:"
|
268
|
+
|
269
|
+
## auto-add/register sig(nature) in here - why? why not?
|
270
|
+
## fix-fix-fix - check if outputs is an array (or still single type?)
|
271
|
+
contract_class.sigs[ name ] = { inputs: [],
|
272
|
+
outputs: [typeof(type)],
|
273
|
+
options: [:view, :public] }
|
274
|
+
contract_class.sigs_exclude << name
|
275
|
+
|
276
|
+
|
277
|
+
contract_class.class_eval do
|
278
|
+
define_method name do
|
279
|
+
puts "[debug] call public (state) getter for #{name} : #{type} (#{contract_class.name})"
|
280
|
+
puts "[debug] self -> #{self}"
|
281
|
+
value = instance_variable_get( :"@#{name}" )
|
282
|
+
value
|
283
|
+
end
|
284
|
+
end # class_eval
|
285
|
+
|
286
|
+
## auto-add typed wrapper!!!!!
|
287
|
+
typed_function( contract_class, name, inputs: [] )
|
288
|
+
end # if
|
289
|
+
|
290
|
+
## puts "after - instance_methods:"
|
291
|
+
## pp contract_class.instance_methods( false )
|
292
|
+
end # method getter_function
|
293
|
+
|
294
|
+
|
295
|
+
|
296
|
+
def self.mapping_getter_function( contract_class, name, type )
|
297
|
+
## note: make sure name is always a symbol
|
298
|
+
name = name.to_sym
|
299
|
+
|
300
|
+
index = 0
|
301
|
+
current_type = type
|
302
|
+
|
303
|
+
sig_args = []
|
304
|
+
while current_type.mapping? do
|
305
|
+
sig_args << current_type.key_type
|
306
|
+
current_type = current_type.value_type
|
307
|
+
index += 1
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
puts "[debug] auto-generate public mapping getter - #{name} : #{type} (#{contract_class.name}):"
|
312
|
+
puts "sig_args:"
|
313
|
+
pp sig_args
|
314
|
+
## auto-add/register sig(nature) in here - why? why not?
|
315
|
+
## contract_class.sig( name, sig_args, :view, returns: current_type)
|
316
|
+
puts " index: #{index}"
|
317
|
+
# {:arg0=>:address}
|
318
|
+
# index: 1
|
319
|
+
|
320
|
+
## check - if sig_args is alreay array of types (or typedclasses???)
|
321
|
+
sig_args = sig_args.map {|sig_arg| typeof(sig_arg) }
|
322
|
+
|
323
|
+
contract_class.sigs[ name ] = { inputs: sig_args,
|
324
|
+
outputs: [typeof(current_type)],
|
325
|
+
options: [:view, :public] }
|
326
|
+
contract_class.sigs_exclude << name
|
327
|
+
|
328
|
+
|
329
|
+
puts contract_class.sigs[ name ].pretty_print_inspect
|
330
|
+
|
331
|
+
|
332
|
+
contract_class.class_eval do
|
333
|
+
## note: hack: must use kwargs for now!!! arg0, arg1, arg2, for now
|
334
|
+
define_method name do |arg0:, arg1: nil, arg2: nil, arg3: nil|
|
335
|
+
puts "[debug] call public (state) mapping getter for #{name} : #{type} - index: #{index} (#{contract_class.name})"
|
336
|
+
puts "[debug] self -> #{self}"
|
337
|
+
args = [arg0, arg1, arg2, arg3]
|
338
|
+
puts "[debug] args -> #{args.pretty_print_inspect}"
|
339
|
+
|
340
|
+
## raise ArgumentError, "expected #{index} argument(s); got #{args.size}" if args.size != index
|
341
|
+
|
342
|
+
value = instance_variable_get( "@#{name}" )
|
343
|
+
(0...index).each do |i|
|
344
|
+
value = value[ args[i] ]
|
345
|
+
end
|
346
|
+
value
|
347
|
+
end
|
348
|
+
end # class_eval
|
349
|
+
|
350
|
+
## auto-add typed wrapper!!!!!
|
351
|
+
typed_function( contract_class, name, inputs: sig_args )
|
352
|
+
|
353
|
+
end # method mapping_getter_function
|
354
|
+
|
355
|
+
|
356
|
+
|
357
|
+
##
|
358
|
+
# add global contract function to lookup AND typecheck
|
359
|
+
## contracts using Contract.at
|
360
|
+
## add via Module and Kernel - why? why not?
|
361
|
+
module Globals
|
362
|
+
end # module Globals
|
363
|
+
|
364
|
+
## todo/check: move Kernel include to rubidity.rb script (with requires) - why? why not?
|
365
|
+
::Kernel.include( Globals )
|
366
|
+
|
367
|
+
def self.global_function( contract_class )
|
368
|
+
## todo/check: check if method exists already - why? why not?
|
369
|
+
|
370
|
+
contract_name = _demodulize( contract_class.name ).to_sym
|
371
|
+
|
372
|
+
## use module_eval if exists? why? why not?
|
373
|
+
## example:
|
374
|
+
## def ERC20( address )
|
375
|
+
## klass = ERC20
|
376
|
+
## puts "==> calling #{klass.name}( #{address.pretty_print_inspect })"
|
377
|
+
## obj = klass.at( address )
|
378
|
+
## raise ArgumentError, "no #{klass.name} contract @ addreess #{address} found; sorry" if obj.nil?
|
379
|
+
## puts " bingo! #{obj.class.name} (#{obj.class.parent_contracts}) contract found @ #{address}"
|
380
|
+
## obj
|
381
|
+
## end
|
382
|
+
Globals.class_eval do
|
383
|
+
define_method contract_name do |address|
|
384
|
+
klass = contract_class
|
385
|
+
puts "==> calling #{klass.name}( #{address.pretty_print_inspect })"
|
386
|
+
obj = klass.at( address )
|
387
|
+
raise ArgumentError, "no #{klass.name} contract @ address #{address} found; sorry" if obj.nil?
|
388
|
+
puts " bingo! #{obj.class.name} (#{obj.class.parent_contracts}) contract found @ #{address}"
|
389
|
+
obj
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end # module Generator
|
394
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
|
2
|
+
module Library
|
3
|
+
|
4
|
+
def self.extended(base)
|
5
|
+
puts "==> turn (extend) module >#{base.name}< into library"
|
6
|
+
base.include( Types ) ## make solidity types availbe (Address, Bytes, etc.)
|
7
|
+
base.extend( ClassMethods )
|
8
|
+
## todo/fix: add runtime and crypto methods too? why? why not?
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def struct( class_name, **attributes )
|
14
|
+
typedclass = Types::Struct.new( class_name, scope: self, **attributes )
|
15
|
+
typedclass
|
16
|
+
end
|
17
|
+
|
18
|
+
def enum( class_name, *args )
|
19
|
+
typedclass = Types::Enum.new( class_name, *args, scope: self )
|
20
|
+
typedclass
|
21
|
+
end
|
22
|
+
|
23
|
+
####
|
24
|
+
# note: sig machinery with method_added MUST come last here
|
25
|
+
def sigs
|
26
|
+
@sigs ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def sigs_unnamed ## unnamed sigs stack
|
30
|
+
@sigs_unnamed ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
## ignore this methods;
|
34
|
+
## do NOT (auto-)generate wrapper method popping (unnamed) sig from stack!!!
|
35
|
+
def sigs_exclude
|
36
|
+
## note: always exclude globals
|
37
|
+
## get or can get changed via runtime modules (simulacrm) and such!!!
|
38
|
+
## e.g. msg.sender, block.timestamp, tx.origin, etc.
|
39
|
+
@sigs_exclude ||= [:block, :tx, :msg]
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
def sig( args=[], *options, returns: nil )
|
45
|
+
|
46
|
+
puts "[debug] add sig args: #{args.inspect}, options: #{options.inspect}, returns: #{returns.inspect}"
|
47
|
+
## use inputs for args) and outputs for returns - why? why not?
|
48
|
+
|
49
|
+
## check if include explicit visibility in options
|
50
|
+
if options.include?( :public ) ||
|
51
|
+
options.include?( :private ) ||
|
52
|
+
options.include?( :internal )
|
53
|
+
# do nothing / pass-along as is
|
54
|
+
else
|
55
|
+
# auto-add default up-front - :public or :internal if name starting with underscore (_)
|
56
|
+
visibility = name.start_with?( '_' ) ? :internal : :public
|
57
|
+
options.unshift( visibility )
|
58
|
+
end
|
59
|
+
|
60
|
+
####
|
61
|
+
# auto-convert args (inputs), returns (outputs) to type (defs)
|
62
|
+
args = args.map { |value| typeof( value ) }
|
63
|
+
|
64
|
+
###
|
65
|
+
## note: turn returns into an array - empty if nil, etc.
|
66
|
+
## always wrap into array
|
67
|
+
returns = if returns.nil?
|
68
|
+
[]
|
69
|
+
elsif returns.is_a?( ::Array )
|
70
|
+
returns
|
71
|
+
else ## assume single type
|
72
|
+
[returns]
|
73
|
+
end
|
74
|
+
|
75
|
+
returns = returns.map { |value| typeof( value ) }
|
76
|
+
|
77
|
+
|
78
|
+
@sigs_unnamed ||= []
|
79
|
+
@sigs_unnamed.push( { inputs: args,
|
80
|
+
outputs: returns,
|
81
|
+
options: options } )
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
def method_added( name )
|
87
|
+
|
88
|
+
if sigs_exclude.include?( name )
|
89
|
+
puts "--- skip method added hook >#{name}< - found in sigs exclude"
|
90
|
+
return ## do nothing;
|
91
|
+
else
|
92
|
+
puts "==> method added hook >#{name}<... processing..."
|
93
|
+
end
|
94
|
+
|
95
|
+
## pp name
|
96
|
+
## pp name.class.name
|
97
|
+
|
98
|
+
name = name.to_sym ## note: make sure name is ALWAYS a symbol
|
99
|
+
|
100
|
+
## note: method lookup via method needs an object / INSTANCE
|
101
|
+
## NOT working with class only!!!!
|
102
|
+
|
103
|
+
# m = method( name )
|
104
|
+
# pp m.name
|
105
|
+
# pp m.parameters
|
106
|
+
# pp m
|
107
|
+
|
108
|
+
raise "no unnamed sig(nature) on stack for method >#{name}< in module >#{self.name}<; sorry" if sigs_unnamed.size == 0
|
109
|
+
sig_unnamed = sigs_unnamed.pop
|
110
|
+
puts " using sig_unnamed: #{sig_unnamed.inspect}"
|
111
|
+
|
112
|
+
|
113
|
+
@sigs ||= {}
|
114
|
+
raise "duplicate method sig(nature) for method >#{name}< in module >#{self.name}<; sorry" if @sigs.has_key?( name )
|
115
|
+
@sigs[ name ] = sig_unnamed
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
puts " generate typed_library_function >#{name}<"
|
120
|
+
Generator.typed_library_function( self, name,
|
121
|
+
inputs: sig_unnamed[ :inputs ] )
|
122
|
+
|
123
|
+
puts "<== method added hook >#{name}< done."
|
124
|
+
end
|
125
|
+
end # module ClassMethods
|
126
|
+
end # module Library
|
@@ -0,0 +1,82 @@
|
|
1
|
+
## todo/ find a better name - why? why not?
|
2
|
+
## change to Blockchain/Chain/Node/Client/Runner/Ctx/Context or ???
|
3
|
+
class Runtime
|
4
|
+
|
5
|
+
|
6
|
+
class Message
|
7
|
+
attr_reader :sender
|
8
|
+
|
9
|
+
def sender=(address)
|
10
|
+
## note: allow literal and typed address
|
11
|
+
@sender = address.is_a?( Types::Address) ?
|
12
|
+
address : Types::Address.new( address )
|
13
|
+
end
|
14
|
+
end # class Message
|
15
|
+
|
16
|
+
|
17
|
+
class Tx
|
18
|
+
attr_reader :origin
|
19
|
+
def origin=(address)
|
20
|
+
@origin = address.is_a?( Types::Address ) ?
|
21
|
+
address : Types::Address.new( address )
|
22
|
+
end
|
23
|
+
|
24
|
+
def log_event( event )
|
25
|
+
puts "==> log_event:"
|
26
|
+
pp event
|
27
|
+
end
|
28
|
+
=begin
|
29
|
+
def log_event(event)
|
30
|
+
call_receipt.logs << event
|
31
|
+
event
|
32
|
+
end
|
33
|
+
=end
|
34
|
+
end # class Tx
|
35
|
+
|
36
|
+
|
37
|
+
class Block
|
38
|
+
attr_accessor :number, :timestamp
|
39
|
+
|
40
|
+
# def initialize(current_transaction)
|
41
|
+
# @current_transaction = current_transaction
|
42
|
+
# end
|
43
|
+
|
44
|
+
def blockhash( block_number )
|
45
|
+
##
|
46
|
+
# unless @current_transaction.ethscription.block_number == block_number.value # TODO FIX
|
47
|
+
# raise "Not implemented"
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# @current_transaction.ethscription.block_blockhash
|
51
|
+
|
52
|
+
# todo - check what ("dummy") to return here??
|
53
|
+
end
|
54
|
+
|
55
|
+
def number=(number)
|
56
|
+
@number = number.is_a?( Types::UInt ) ?
|
57
|
+
number : Types::UInt.new( number )
|
58
|
+
end
|
59
|
+
|
60
|
+
def timestamp=(timestamp)
|
61
|
+
@timestamp = timestamp.is_a?( Types::Timestamp ) ?
|
62
|
+
timestamp : Types::Timestamp.new( timestamp )
|
63
|
+
end
|
64
|
+
end # class Block
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
def self.msg() @msg ||= Message.new; end
|
69
|
+
def self.block() @block ||= Block.new; end
|
70
|
+
|
71
|
+
|
72
|
+
## use begin_transaction or
|
73
|
+
## new_transaction or __ - why? why not?
|
74
|
+
def self.start_transaction() @tx = Tx.new; end
|
75
|
+
def self.current_transaction() @tx ||= Tx.new; end
|
76
|
+
|
77
|
+
class << self
|
78
|
+
alias_method :start_tx, :start_transaction
|
79
|
+
alias_method :current_tx, :current_transaction
|
80
|
+
end
|
81
|
+
end # class Runtime
|
82
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rubysol
|
2
|
+
module Module
|
3
|
+
module Lang
|
4
|
+
MAJOR = 0
|
5
|
+
MINOR = 1
|
6
|
+
PATCH = 0
|
7
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
8
|
+
|
9
|
+
def self.version
|
10
|
+
VERSION
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.banner
|
14
|
+
"rubysol/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.root
|
18
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(File.dirname(__FILE__)))) )
|
19
|
+
end
|
20
|
+
|
21
|
+
end # module Lang
|
22
|
+
end # module Module
|
23
|
+
end # module Rubysol
|