universum 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +16 -0
- data/README.md +34 -35
- data/Rakefile +1 -1
- data/lib/universum.rb +19 -0
- data/lib/universum/account.rb +52 -0
- data/lib/universum/address.rb +75 -0
- data/lib/universum/contract.rb +87 -0
- data/lib/universum/function.rb +10 -0
- data/lib/universum/receipt.rb +52 -0
- data/lib/universum/safe_array.rb +69 -0
- data/lib/universum/safe_hash.rb +77 -0
- data/lib/universum/transaction.rb +89 -0
- data/lib/universum/type.rb +49 -0
- data/lib/universum/units_money.rb +64 -0
- data/lib/universum/units_time.rb +51 -0
- data/lib/universum/universum.rb +0 -394
- data/lib/universum/version.rb +2 -2
- data/test/contracts/greeter.rb +12 -13
- data/test/contracts/mytoken.rb +13 -14
- data/test/test_array.rb +52 -0
- data/test/test_greeter.rb +2 -2
- data/test/test_hash.rb +84 -0
- data/test/test_struct.rb +35 -0
- data/test/test_units_money.rb +60 -0
- data/test/test_units_time.rb +75 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db4bf31c857f63ae6e203d9ddcdb718556c6f2a7
|
4
|
+
data.tar.gz: 3989ec1e3962f0768a8a3c108e72a76b4c4b969b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 276c1b77f06cf0e0dcb10a7a4ca4ef072365f1852c30e5b83279582f4d38447ad178c975c9e169e40aef5871a8d830cd8748d371c9d5846f3fd3211fe251ed07
|
7
|
+
data.tar.gz: 7086a5e4984497cc116ee05eb397a34afc7e766474e5aacc802421a37c16c5c4031936dae03fbdecd8b9172c5d990c52391dc3a18b14620d4ae92b26e46405e4
|
data/Manifest.txt
CHANGED
@@ -4,14 +4,30 @@ Manifest.txt
|
|
4
4
|
README.md
|
5
5
|
Rakefile
|
6
6
|
lib/universum.rb
|
7
|
+
lib/universum/account.rb
|
8
|
+
lib/universum/address.rb
|
9
|
+
lib/universum/contract.rb
|
7
10
|
lib/universum/enum.rb
|
8
11
|
lib/universum/event.rb
|
12
|
+
lib/universum/function.rb
|
13
|
+
lib/universum/receipt.rb
|
14
|
+
lib/universum/safe_array.rb
|
15
|
+
lib/universum/safe_hash.rb
|
16
|
+
lib/universum/transaction.rb
|
17
|
+
lib/universum/type.rb
|
18
|
+
lib/universum/units_money.rb
|
19
|
+
lib/universum/units_time.rb
|
9
20
|
lib/universum/universum.rb
|
10
21
|
lib/universum/version.rb
|
11
22
|
test/contracts/greeter.rb
|
12
23
|
test/contracts/mytoken.rb
|
13
24
|
test/helper.rb
|
25
|
+
test/test_array.rb
|
14
26
|
test/test_enum.rb
|
15
27
|
test/test_event.rb
|
16
28
|
test/test_greeter.rb
|
29
|
+
test/test_hash.rb
|
30
|
+
test/test_struct.rb
|
31
|
+
test/test_units_money.rb
|
32
|
+
test/test_units_time.rb
|
17
33
|
test/test_version.rb
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
New to Universum? See the [Universum (World Computer) White Paper](https://github.com/
|
1
|
+
New to Universum? See the [Universum (World Computer) White Paper](https://github.com/s6ruby/universum/blob/master/WHITEPAPER.md)!
|
2
2
|
|
3
3
|
|
4
4
|
|
@@ -7,8 +7,8 @@ New to Universum? See the [Universum (World Computer) White Paper](https://githu
|
|
7
7
|
next generation ethereum 2.0 world computer runtime - run contract scripts / transactions in plain vanilla / standard ruby on the blockchain - update the (contract-protected / isolated) world states with plain vanilla / standard SQL
|
8
8
|
|
9
9
|
|
10
|
-
* home :: [github.com/
|
11
|
-
* bugs :: [github.com/
|
10
|
+
* home :: [github.com/s6ruby/universum](https://github.com/s6ruby/universum)
|
11
|
+
* bugs :: [github.com/s6ruby/universum/issues](https://github.com/s6ruby/universum/issues)
|
12
12
|
* gem :: [rubygems.org/gems/universum](https://rubygems.org/gems/universum)
|
13
13
|
* rdoc :: [rubydoc.info/gems/universum](http://rubydoc.info/gems/universum)
|
14
14
|
|
@@ -56,21 +56,21 @@ contract Greeter is Mortal {
|
|
56
56
|
and
|
57
57
|
|
58
58
|
``` ruby
|
59
|
-
|
59
|
+
##################
|
60
|
+
# Greeter Contract
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
def initialize( greeting )
|
63
|
+
@owner = msg.sender
|
64
|
+
@greeting = greeting
|
65
|
+
end
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
67
|
+
def greet
|
68
|
+
@greeting
|
69
|
+
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end # class Greeter
|
71
|
+
def kill
|
72
|
+
selfdestruct( msg.sender ) if msg.sender == @owner
|
73
|
+
end
|
74
74
|
```
|
75
75
|
|
76
76
|
(Source: [`contracts/greeter.rb`](test/contracts/greeter.rb))
|
@@ -82,18 +82,17 @@ And let's run the greeter with Universum (Uni):
|
|
82
82
|
``` ruby
|
83
83
|
require 'universum'
|
84
84
|
|
85
|
-
require_relative 'greeter'
|
86
|
-
|
87
|
-
|
88
85
|
Account['0x1111'] ## setup a test account
|
89
86
|
|
90
|
-
|
87
|
+
## create contract (english version)
|
88
|
+
tx = Uni.send_transaction( from: '0x1111', data: ['./greeter', 'Hello World!'] )
|
91
89
|
greeter = tx.receipt.contract
|
92
90
|
|
93
91
|
puts greeter.greet
|
94
92
|
#=> Hello World!
|
95
93
|
|
96
|
-
|
94
|
+
## create contract (spanish version)
|
95
|
+
tx = Uni.send_transaction( from: '0x1111', data: ['./greeter', '¡Hola, mundo!'] )
|
97
96
|
greeter_es = Receipt[ tx ].contract
|
98
97
|
|
99
98
|
puts greeter_es.greet
|
@@ -141,23 +140,23 @@ contract MyToken {
|
|
141
140
|
and
|
142
141
|
|
143
142
|
``` ruby
|
144
|
-
|
143
|
+
############################
|
144
|
+
## My Token Contract
|
145
145
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
146
|
+
def initialize( initial_supply )
|
147
|
+
@balance_of = Mapping.of( Address => Money )
|
148
|
+
@balance_of[ msg.sender] = initial_supply
|
149
|
+
end
|
150
150
|
|
151
|
-
|
152
|
-
|
153
|
-
|
151
|
+
def transfer( to, value )
|
152
|
+
assert @balance_of[ msg.sender ] >= value
|
153
|
+
assert @balance_of[ to ] + value >= @balance_of[ to ]
|
154
154
|
|
155
|
-
|
156
|
-
|
155
|
+
@balance_of[ msg.sender ] -= value
|
156
|
+
@balance_of[ to ] += value
|
157
157
|
|
158
|
-
|
159
|
-
|
160
|
-
end # class MyToken
|
158
|
+
true
|
159
|
+
end
|
161
160
|
```
|
162
161
|
|
163
162
|
(Source: [`contracts/mytoken.rb`](test/contracts/mytoken.rb))
|
@@ -167,12 +166,12 @@ end # class MyToken
|
|
167
166
|
|
168
167
|
## More Contract Samples
|
169
168
|
|
170
|
-
See the [`/universum-contracts`](https://github.com/
|
169
|
+
See the [`/universum-contracts`](https://github.com/s6ruby/universum-contracts) collection.
|
171
170
|
|
172
171
|
|
173
172
|
## More Documentation / Articles / Contracts
|
174
173
|
|
175
|
-
[Programming Crypto Blockchain Contracts Step-by-Step Book / Guide](https://github.com/
|
174
|
+
[Programming Crypto Blockchain Contracts Step-by-Step Book / Guide](https://github.com/s6ruby/programming-cryptocontracts) - Let's Start with Ponzi & Pyramid Schemes. Run Your Own Lotteries, Gambling Casinos and more on the Blockchain World Computer...
|
176
175
|
|
177
176
|
|
178
177
|
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Hoe.spec 'universum' do
|
|
8
8
|
self.summary = "universum - next generation ethereum 2.0 world computer runtime; run contract scripts / transactions in plain vanilla / standard ruby on the blockchain; update the (contract-protected / isolated) world states with plain vanilla / standard SQL"
|
9
9
|
self.description = summary
|
10
10
|
|
11
|
-
self.urls = ['https://github.com/
|
11
|
+
self.urls = ['https://github.com/s6ruby/universum']
|
12
12
|
|
13
13
|
self.author = 'Gerald Bauer'
|
14
14
|
self.email = 'wwwmake@googlegroups.com'
|
data/lib/universum.rb
CHANGED
@@ -4,14 +4,33 @@
|
|
4
4
|
## stdlibs
|
5
5
|
require 'pp' ## pretty print (pp)
|
6
6
|
require 'digest'
|
7
|
+
require 'date'
|
8
|
+
require 'time'
|
9
|
+
require 'uri'
|
10
|
+
|
7
11
|
|
8
12
|
|
9
13
|
## our own code
|
10
14
|
require 'universum/version' # note: let version always go first
|
11
15
|
|
16
|
+
require 'universum/units_time'
|
17
|
+
require 'universum/units_money'
|
18
|
+
|
19
|
+
require 'universum/safe_array'
|
20
|
+
require 'universum/safe_hash'
|
21
|
+
|
12
22
|
require 'universum/enum'
|
13
23
|
require 'universum/event'
|
14
24
|
|
25
|
+
require 'universum/function'
|
26
|
+
require 'universum/address'
|
27
|
+
require 'universum/type'
|
28
|
+
require 'universum/account'
|
29
|
+
require 'universum/contract'
|
30
|
+
require 'universum/transaction'
|
31
|
+
require 'universum/receipt'
|
32
|
+
|
33
|
+
|
15
34
|
require 'universum/universum'
|
16
35
|
|
17
36
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
class Account
|
5
|
+
|
6
|
+
@@directory = {}
|
7
|
+
def self.find_by_address( key )
|
8
|
+
## clean key (allow "embedded" name e.g 0x1111 (Alice))
|
9
|
+
key = key.gsub(/\(.+\)/, '' ).strip
|
10
|
+
@@directory[ key ]
|
11
|
+
end
|
12
|
+
def self.find( key ) find_by_address( key ); end # make find_by_address the default finder
|
13
|
+
def self.at( key) find_by_address( key ); end # another "classic" alias for find_by_address
|
14
|
+
|
15
|
+
def self.[]( key )
|
16
|
+
o = find_by_address( key )
|
17
|
+
if o
|
18
|
+
o
|
19
|
+
else
|
20
|
+
o = new( key )
|
21
|
+
## note: auto-register (new) address in (yellow page) directory
|
22
|
+
@@directory[ key ] = o
|
23
|
+
o
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.all() @@directory.values; end
|
28
|
+
|
29
|
+
|
30
|
+
####
|
31
|
+
# account (builtin) services / transaction methods
|
32
|
+
include Address ## includes address + send/transfer/balance
|
33
|
+
|
34
|
+
## note: for now allow write access too!!!
|
35
|
+
def balance=( value )
|
36
|
+
@balance = value
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :tx
|
40
|
+
def _auto_inc_tx() @tx += 1; end ## "internal" method - (auto) increment transaction (tx) counter
|
41
|
+
|
42
|
+
## note: needed by transfer/send
|
43
|
+
def this() Universum.this; end ## returns current contract
|
44
|
+
|
45
|
+
private
|
46
|
+
def initialize( address, balance: 0, tx: 0 )
|
47
|
+
@address = address # type address - (hex) string starts with 0x
|
48
|
+
@balance = balance # uint
|
49
|
+
@tx = tx # transaction (tx) count (used for nonce and replay attack protection)
|
50
|
+
end
|
51
|
+
|
52
|
+
end # class Account
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
#############
|
5
|
+
# FIX/FIX/FIX!!!! - turn Address into a class!!!!
|
6
|
+
|
7
|
+
|
8
|
+
module Address
|
9
|
+
def self.zero() '0x0000'; end
|
10
|
+
|
11
|
+
def address
|
12
|
+
if @address
|
13
|
+
@address
|
14
|
+
else
|
15
|
+
if is_a? Contract
|
16
|
+
## fix/todo: use/lookup proper addr from contract
|
17
|
+
## construct address for now from object_id
|
18
|
+
"0x#{(object_id << 1).to_s(16)}"
|
19
|
+
else ## assume Account
|
20
|
+
'0x0000'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end # method address
|
24
|
+
|
25
|
+
def transfer( value ) ## @payable @public
|
26
|
+
## todo/fix: throw exception if insufficient funds
|
27
|
+
send( value ) # returns true/false
|
28
|
+
end
|
29
|
+
|
30
|
+
def send( value ) ## @payable @public
|
31
|
+
## todo/fix: assert value > 0
|
32
|
+
## todo/fix: add missing -= part in transfer!!!!
|
33
|
+
|
34
|
+
## use this (current contract) for debit (-) ammount
|
35
|
+
this._sub( value ) # sub(tract) / debit from the sender (current contract)
|
36
|
+
_add( value ) # add / credit to the recipient
|
37
|
+
end
|
38
|
+
|
39
|
+
def balance
|
40
|
+
@balance ||= 0 ## return 0 if undefined
|
41
|
+
end
|
42
|
+
|
43
|
+
### private (internal use only) methods - PLEASE do NOT use (use transfer/send)
|
44
|
+
def _sub( value )
|
45
|
+
@balance ||= 0 ## return 0 if undefined
|
46
|
+
@balance -= value
|
47
|
+
end
|
48
|
+
|
49
|
+
def _add( value )
|
50
|
+
@balance ||= 0 ## return 0 if undefined
|
51
|
+
@balance += value
|
52
|
+
end
|
53
|
+
end # module Address
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
class String
|
58
|
+
def transfer( value )
|
59
|
+
## check if self is an address
|
60
|
+
if self.start_with?( '0x' )
|
61
|
+
Account[self].transfer( value )
|
62
|
+
else
|
63
|
+
raise "(Auto-)Type Conversion from Address (Hex) String to Account Failed; Expected String Starting with 0x got #{self}; Contract Halted (Stopped)"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def send( value )
|
68
|
+
## check if self is an address
|
69
|
+
if self.start_with?( '0x' )
|
70
|
+
Account[self].send( value )
|
71
|
+
else
|
72
|
+
raise "(Auto-)Type Conversion from Address (Hex) String to Account Failed; Expected String Starting with 0x got #{self}; Contract Halted (Stopped)"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
class Contract
|
5
|
+
|
6
|
+
#########
|
7
|
+
# load "class-less" contract
|
8
|
+
# e.g. SathoshiDice = Contract.load( './sathoshi_dice' )
|
9
|
+
def self.load( path )
|
10
|
+
extname = File.extname( path ) #=> ".rb"
|
11
|
+
if extname == '.rb'
|
12
|
+
## do nothing
|
13
|
+
else
|
14
|
+
## "convenience" helper - (auto-)add .rb extension
|
15
|
+
path = "#{path}.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
code = File.open( path, 'r:bom|utf-8' ) { |f| f.read }
|
19
|
+
klass = Class.new( Contract )
|
20
|
+
klass.class_eval( code ) ## note: use class_eval (NOT instance_eval)
|
21
|
+
klass
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
@@directory = {}
|
26
|
+
def self.find_by_address( key )
|
27
|
+
## clean key (allow "embedded" class name e.g 0x4de2ee8 (SatoshiDice))
|
28
|
+
key = key.gsub(/\(.+\)/, '' ).strip
|
29
|
+
@@directory[ key ];
|
30
|
+
end
|
31
|
+
def self.find( key ) find_by_address( key ); end # make find_by_address the default finder
|
32
|
+
def self.at( key) find_by_address( key ); end # another "classic" alias for find_by_address
|
33
|
+
def self.[]( key ) find_by_address( key ); end
|
34
|
+
|
35
|
+
def self.store( key, o ) @@directory.store( key, o ); end ## store (add) new contract object (o) to hash / directory
|
36
|
+
def self.all() @@directory.values; end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
####
|
41
|
+
# account (builtin) services / transaction methods
|
42
|
+
include Address ## includes address + send/transfer/balance
|
43
|
+
|
44
|
+
## function sig(nature) macro for types (dummy for now)
|
45
|
+
# e.g. use like
|
46
|
+
# payable :process
|
47
|
+
# payable :initialize
|
48
|
+
# payable :bet, Integer
|
49
|
+
# payable :lend_money, Address => Bool ## returns Bool
|
50
|
+
def self.payable( *args ); end
|
51
|
+
|
52
|
+
payable :receive
|
53
|
+
|
54
|
+
####
|
55
|
+
# todo/double check: auto-add payable default fallback - why? why not?
|
56
|
+
def receive ## @payable default fallback - use different name - why? why not? (e.g. handle/process/etc.)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def assert( condition )
|
61
|
+
if condition == true
|
62
|
+
## do nothing
|
63
|
+
else
|
64
|
+
raise 'Contract Assertion Failed; Contract Halted (Stopped)'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def this() Universum.this; end ## returns current contract
|
70
|
+
def log( event ) Universum.log( event ); end
|
71
|
+
def msg() Universum.msg; end
|
72
|
+
def block() Universum.block; end
|
73
|
+
def blockhash( number )
|
74
|
+
## todo/fix: only allow going back 255 blocks; check if number is in range!!!
|
75
|
+
Universum.blockhash( number )
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def selfdestruct( owner ) ## todo/check: use a different name e.g. destruct/ delete - why? why not?
|
80
|
+
## selfdestruct function (for clean-up on blockchain)
|
81
|
+
owner.send( @balance ) ## send back all funds owned/hold by contract
|
82
|
+
|
83
|
+
## fix: does nothing for now - add some code (e.g. cleanup)
|
84
|
+
## mark as destruct - why? why not?
|
85
|
+
end
|
86
|
+
|
87
|
+
end # class Contract
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
class Receipt ## transaction receipt
|
5
|
+
|
6
|
+
@@directory = {}
|
7
|
+
def self.find( tx )
|
8
|
+
key = "#{tx.from}/#{tx.nonce}"
|
9
|
+
@@directory[ key ];
|
10
|
+
end
|
11
|
+
def self.[]( tx ) find( tx ); end
|
12
|
+
|
13
|
+
def self.store( o )
|
14
|
+
key = "#{o.from}/#{o.nonce}"
|
15
|
+
@@directory.store( key, o ); end ## store (add) new receipt object (o) to hash / directory
|
16
|
+
def self.all() @@directory.values; end
|
17
|
+
|
18
|
+
|
19
|
+
## required attributes / fields
|
20
|
+
attr_reader :nonce, :from, :to, :value,
|
21
|
+
:block_number
|
22
|
+
## optional
|
23
|
+
attr_reader :contract_address
|
24
|
+
|
25
|
+
def initialize( tx:,
|
26
|
+
block:,
|
27
|
+
contract: nil )
|
28
|
+
@nonce = tx.nonce
|
29
|
+
@from = tx.from
|
30
|
+
@to = tx.to
|
31
|
+
@value = tx.value
|
32
|
+
## todo/fix: add data too!!!
|
33
|
+
|
34
|
+
@block_number = block.number
|
35
|
+
## todo/fix: add block_hash
|
36
|
+
|
37
|
+
if contract
|
38
|
+
## note: for easier debugging add class name in () to address (needs to get stripped away in lookup)
|
39
|
+
@contract_address = "#{contract.address} (#{contract.class.name})"
|
40
|
+
else
|
41
|
+
@contract_address = nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def contract # convenience helper (quick contract lookup)
|
46
|
+
if @contract_address
|
47
|
+
Contract.find( @contract_address )
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|