ruby-ethereum 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/lib/ethereum.rb +53 -0
- data/lib/ethereum/abi.rb +333 -0
- data/lib/ethereum/abi/contract_translator.rb +174 -0
- data/lib/ethereum/abi/type.rb +117 -0
- data/lib/ethereum/account.rb +72 -0
- data/lib/ethereum/address.rb +60 -0
- data/lib/ethereum/base_convert.rb +53 -0
- data/lib/ethereum/block.rb +1311 -0
- data/lib/ethereum/block_header.rb +211 -0
- data/lib/ethereum/bloom.rb +83 -0
- data/lib/ethereum/cached_block.rb +36 -0
- data/lib/ethereum/chain.rb +400 -0
- data/lib/ethereum/constant.rb +26 -0
- data/lib/ethereum/core_ext/array/safe_slice.rb +18 -0
- data/lib/ethereum/core_ext/module/lru_cache.rb +20 -0
- data/lib/ethereum/core_ext/numeric/denominations.rb +45 -0
- data/lib/ethereum/core_ext/object/truth.rb +47 -0
- data/lib/ethereum/db.rb +6 -0
- data/lib/ethereum/db/base_db.rb +9 -0
- data/lib/ethereum/db/ephem_db.rb +63 -0
- data/lib/ethereum/db/overlay_db.rb +72 -0
- data/lib/ethereum/db/refcount_db.rb +188 -0
- data/lib/ethereum/env.rb +64 -0
- data/lib/ethereum/ethash.rb +78 -0
- data/lib/ethereum/ethash_ruby.rb +38 -0
- data/lib/ethereum/ethash_ruby/cache.rb +47 -0
- data/lib/ethereum/ethash_ruby/hashimoto.rb +75 -0
- data/lib/ethereum/ethash_ruby/utils.rb +53 -0
- data/lib/ethereum/exceptions.rb +28 -0
- data/lib/ethereum/external_call.rb +173 -0
- data/lib/ethereum/fast_rlp.rb +81 -0
- data/lib/ethereum/fast_vm.rb +625 -0
- data/lib/ethereum/fast_vm/call_data.rb +44 -0
- data/lib/ethereum/fast_vm/message.rb +29 -0
- data/lib/ethereum/fast_vm/state.rb +25 -0
- data/lib/ethereum/ffi/openssl.rb +390 -0
- data/lib/ethereum/index.rb +97 -0
- data/lib/ethereum/log.rb +43 -0
- data/lib/ethereum/miner.rb +84 -0
- data/lib/ethereum/opcodes.rb +131 -0
- data/lib/ethereum/private_key.rb +92 -0
- data/lib/ethereum/pruning_trie.rb +28 -0
- data/lib/ethereum/public_key.rb +88 -0
- data/lib/ethereum/receipt.rb +53 -0
- data/lib/ethereum/secp256k1.rb +58 -0
- data/lib/ethereum/secure_trie.rb +49 -0
- data/lib/ethereum/sedes.rb +42 -0
- data/lib/ethereum/special_contract.rb +95 -0
- data/lib/ethereum/spv.rb +79 -0
- data/lib/ethereum/spv/proof.rb +31 -0
- data/lib/ethereum/spv/proof_constructor.rb +19 -0
- data/lib/ethereum/spv/proof_verifier.rb +24 -0
- data/lib/ethereum/tester.rb +14 -0
- data/lib/ethereum/tester/abi_contract.rb +65 -0
- data/lib/ethereum/tester/fixture.rb +31 -0
- data/lib/ethereum/tester/language.rb +30 -0
- data/lib/ethereum/tester/log_recorder.rb +13 -0
- data/lib/ethereum/tester/solidity_wrapper.rb +144 -0
- data/lib/ethereum/tester/state.rb +194 -0
- data/lib/ethereum/transaction.rb +196 -0
- data/lib/ethereum/transient_trie.rb +28 -0
- data/lib/ethereum/trie.rb +549 -0
- data/lib/ethereum/trie/nibble_key.rb +184 -0
- data/lib/ethereum/utils.rb +191 -0
- data/lib/ethereum/version.rb +5 -0
- data/lib/ethereum/vm.rb +606 -0
- data/lib/ethereum/vm/call_data.rb +40 -0
- data/lib/ethereum/vm/message.rb +30 -0
- data/lib/ethereum/vm/state.rb +25 -0
- metadata +284 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module Constant
|
5
|
+
|
6
|
+
BYTE_EMPTY = "".freeze
|
7
|
+
BYTE_ZERO = "\x00".freeze
|
8
|
+
BYTE_ONE = "\x01".freeze
|
9
|
+
|
10
|
+
TT32 = 2**32
|
11
|
+
TT256 = 2**256
|
12
|
+
TT64M1 = 2**64 - 1
|
13
|
+
|
14
|
+
UINT_MAX = 2**256 - 1
|
15
|
+
UINT_MIN = 0
|
16
|
+
INT_MAX = 2**255 - 1
|
17
|
+
INT_MIN = -2**255
|
18
|
+
|
19
|
+
HASH_ZERO = ("\x00"*32).freeze
|
20
|
+
|
21
|
+
PUBKEY_ZERO = ("\x00"*32).freeze
|
22
|
+
PRIVKEY_ZERO = ("\x00"*32).freeze
|
23
|
+
PRIVKEY_ZERO_HEX = ('0'*64).freeze
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
class Array
|
4
|
+
def safe_slice(*args)
|
5
|
+
if args.size == 2
|
6
|
+
return [] if args[1] == 0
|
7
|
+
slice(args[0], args[1]) || []
|
8
|
+
elsif args.size == 1
|
9
|
+
if args[0].instance_of?(Range)
|
10
|
+
slice(args[0]) || []
|
11
|
+
else
|
12
|
+
slice(args[0])
|
13
|
+
end
|
14
|
+
else
|
15
|
+
slice(*args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
require 'lru_redux'
|
4
|
+
|
5
|
+
class Module
|
6
|
+
|
7
|
+
def lru_cache(meth, n)
|
8
|
+
@_lru_caches ||= {}
|
9
|
+
@_lru_caches[meth] ||= LruRedux::Cache.new n
|
10
|
+
cache = @_lru_caches[meth]
|
11
|
+
|
12
|
+
origin_meth = "#{meth}_without_cache"
|
13
|
+
self.send :alias_method, origin_meth, meth
|
14
|
+
|
15
|
+
self.send(:define_method, meth) do |*args|
|
16
|
+
cache[args] ||= send(origin_meth, *args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
class Numeric
|
4
|
+
|
5
|
+
BABBAGE = 10**3
|
6
|
+
LOVELACE = 10**6
|
7
|
+
SHANNON = 10**9
|
8
|
+
SZABO = 10**12
|
9
|
+
FINNEY = 10**15
|
10
|
+
ETHER = 10**18
|
11
|
+
TURING = 2**256
|
12
|
+
|
13
|
+
def wei
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def babbage
|
18
|
+
self * BABBAGE
|
19
|
+
end
|
20
|
+
|
21
|
+
def lovelace
|
22
|
+
self * LOVELACE
|
23
|
+
end
|
24
|
+
|
25
|
+
def shannon
|
26
|
+
self * SHANNON
|
27
|
+
end
|
28
|
+
|
29
|
+
def szabo
|
30
|
+
self * SZABO
|
31
|
+
end
|
32
|
+
|
33
|
+
def finney
|
34
|
+
self * FINNEY
|
35
|
+
end
|
36
|
+
|
37
|
+
def ether
|
38
|
+
self * ETHER
|
39
|
+
end
|
40
|
+
|
41
|
+
def turing
|
42
|
+
self * TURING
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
class Object
|
4
|
+
def true?
|
5
|
+
!false?
|
6
|
+
end
|
7
|
+
|
8
|
+
def false?
|
9
|
+
respond_to?(:empty?) ? empty? : !self
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Array
|
14
|
+
def false?
|
15
|
+
empty?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class String
|
20
|
+
def false?
|
21
|
+
empty?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class NilClass
|
26
|
+
def false?
|
27
|
+
true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class TrueClass
|
32
|
+
def false?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class FalseClass
|
38
|
+
def false?
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Numeric
|
44
|
+
def false?
|
45
|
+
self == 0
|
46
|
+
end
|
47
|
+
end
|
data/lib/ethereum/db.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module DB
|
5
|
+
class EphemDB < BaseDB
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@db = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(k)
|
12
|
+
@db[k] or raise KeyError, k.inspect
|
13
|
+
end
|
14
|
+
|
15
|
+
def put(k, v)
|
16
|
+
@db[k] = v
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(k)
|
20
|
+
@db.delete(k)
|
21
|
+
end
|
22
|
+
|
23
|
+
def commit
|
24
|
+
# do nothing
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_key?(k)
|
28
|
+
@db.has_key?(k)
|
29
|
+
end
|
30
|
+
alias :include? :has_key?
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
other.instance_of?(self.class) && db == other.db
|
34
|
+
end
|
35
|
+
|
36
|
+
def inc_refcount(k, v)
|
37
|
+
put k, v
|
38
|
+
end
|
39
|
+
|
40
|
+
def dec_refcount(k)
|
41
|
+
# do nothing
|
42
|
+
end
|
43
|
+
|
44
|
+
def revert_refcount_changes(epoch)
|
45
|
+
# do nothing
|
46
|
+
end
|
47
|
+
|
48
|
+
def commit_refcount_changes(epoch)
|
49
|
+
# do nothing
|
50
|
+
end
|
51
|
+
|
52
|
+
def cleanup(epoch)
|
53
|
+
# do nothing
|
54
|
+
end
|
55
|
+
|
56
|
+
def put_temporarily(k, v)
|
57
|
+
inc_refcount(k, v)
|
58
|
+
dec_refcount(k)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module DB
|
5
|
+
##
|
6
|
+
# Used for making temporary objects.
|
7
|
+
#
|
8
|
+
class OverlayDB < BaseDB
|
9
|
+
|
10
|
+
def initialize(db)
|
11
|
+
@db = db
|
12
|
+
@overlay = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(k)
|
16
|
+
if @overlay.has_key?(k)
|
17
|
+
raise KeyError, k.inspect if @overlay[k].nil?
|
18
|
+
return @overlay[k]
|
19
|
+
end
|
20
|
+
|
21
|
+
db.get k
|
22
|
+
end
|
23
|
+
|
24
|
+
def put(k, v)
|
25
|
+
@overlay[k] = v
|
26
|
+
end
|
27
|
+
|
28
|
+
def put_temporarily(k, v)
|
29
|
+
inc_refcount k, v
|
30
|
+
dec_refcount k
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(k)
|
34
|
+
@overlay[k] = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def commit
|
38
|
+
# do nothing
|
39
|
+
end
|
40
|
+
|
41
|
+
def has_key?(k)
|
42
|
+
@overlay.has_key?(k) ? !@overlay[k].nil? : db.has_key?(k)
|
43
|
+
end
|
44
|
+
alias :include? :has_key?
|
45
|
+
|
46
|
+
def ==(other)
|
47
|
+
other.instance_of?(self.class) && db = other.db
|
48
|
+
end
|
49
|
+
|
50
|
+
def inc_refcount(k, v)
|
51
|
+
put k, v
|
52
|
+
end
|
53
|
+
|
54
|
+
def dec_refcount(k)
|
55
|
+
# do nothing
|
56
|
+
end
|
57
|
+
|
58
|
+
def revert_refcount_changes(epoch)
|
59
|
+
# do nothing
|
60
|
+
end
|
61
|
+
|
62
|
+
def commit_refcount_changes(epoch)
|
63
|
+
# do nothing
|
64
|
+
end
|
65
|
+
|
66
|
+
def cleanup(epoch)
|
67
|
+
# do nothing
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module DB
|
5
|
+
class RefcountDB < BaseDB
|
6
|
+
|
7
|
+
DEATH_ROW_OFFSET = 2**62
|
8
|
+
|
9
|
+
ZERO_ENCODED = Utils.encode_int(0)
|
10
|
+
ONE_ENCODED = Utils.encode_int(1)
|
11
|
+
|
12
|
+
def initialize(db)
|
13
|
+
@db = db
|
14
|
+
@journal = []
|
15
|
+
@death_row = []
|
16
|
+
@kv = @db.respond_to?(:kv) ? @db.kv : nil
|
17
|
+
@ttl = 500
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Increase the reference count associated with a key.
|
22
|
+
#
|
23
|
+
def inc_refcount(k, v)
|
24
|
+
node_object = RLP.decode ref_get(k)
|
25
|
+
refcount = Utils.decode_int node_object[0]
|
26
|
+
|
27
|
+
@journal.push [node_object[0], k]
|
28
|
+
refcount = 0 if refcount >= DEATH_ROW_OFFSET
|
29
|
+
|
30
|
+
new_refcount = Utils.encode_int(refcount+1)
|
31
|
+
ref_put k, RLP.encode([new_refcount, v])
|
32
|
+
|
33
|
+
if Logger.trace?(logger.name)
|
34
|
+
logger.trace "increasing #{Utils.encode_hex(k)}=#{v} to #{refcount+1}"
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
ref_put k, RLP.encode([ONE_ENCODED, v])
|
38
|
+
@journal.push [ZERO_ENCODED, k]
|
39
|
+
|
40
|
+
if Logger.trace?(logger.name)
|
41
|
+
logger.trace "increasing #{Utils.encode_hex(k)}=#{v} to 1"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
alias :put :inc_refcount
|
45
|
+
|
46
|
+
##
|
47
|
+
# Decrease the reference count associated with a key.
|
48
|
+
#
|
49
|
+
def dec_refcount(k)
|
50
|
+
node_object = RLP.decode ref_get(k)
|
51
|
+
refcount = Utils.decode_int node_object[0]
|
52
|
+
|
53
|
+
if Logger.trace?(logger.name)
|
54
|
+
logger.trace "decreasing #{Utils.encode_hex(k)} to #{refcount-1}"
|
55
|
+
end
|
56
|
+
|
57
|
+
raise AssertError, "refcount must be greater than zero!" unless refcount > 0
|
58
|
+
|
59
|
+
@journal.push [node_object[0], k]
|
60
|
+
new_refcount = Utils.encode(refcount-1)
|
61
|
+
ref_put k, RLP.encode([new_refcount, node_object[1]])
|
62
|
+
|
63
|
+
@death_row.push k if new_refcount == ZERO_ENCODED
|
64
|
+
end
|
65
|
+
alias :delete :dec_refcount
|
66
|
+
|
67
|
+
def get_refcount(k)
|
68
|
+
o = Utils.decode_int RLP.decode(ref_get(k))[0]
|
69
|
+
o >= DEATH_ROW_OFFSET ? 0 : o
|
70
|
+
rescue
|
71
|
+
0
|
72
|
+
end
|
73
|
+
|
74
|
+
def get(k)
|
75
|
+
RLP.decode(ref_get(k))[1]
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Kill nodes that are eligible to be killed, and remove the associated
|
80
|
+
# deathrow record. Also delete old journals.
|
81
|
+
#
|
82
|
+
def cleanup(epoch)
|
83
|
+
rlp_nodes = @db.get("deathrow:#{epoch}") rescue RLP.encode([])
|
84
|
+
death_row_nodes = RLP.decode rlp_nodes
|
85
|
+
|
86
|
+
pruned = 0
|
87
|
+
offset = DEATH_ROW_OFFSET + epoch
|
88
|
+
|
89
|
+
death_row_nodes.each do |node_key|
|
90
|
+
begin
|
91
|
+
refcount, val = RLP.decode ref_get(node_key)
|
92
|
+
if Utils.decode_int(refcount) == offset
|
93
|
+
@db.delete ref_key(node_key)
|
94
|
+
pruned += 1
|
95
|
+
end
|
96
|
+
rescue
|
97
|
+
logger.debug "in cleanup: #{$!}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
logger.debug "#{pruned} nodes successfully pruned"
|
101
|
+
|
102
|
+
@db.delete "deathrow:#{epoch}" rescue nil
|
103
|
+
@db.delete "journal:#{epoch-@ttl}" rescue nil
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Commit changes to the journal and death row to the database.
|
108
|
+
#
|
109
|
+
def commit_refcount_changes(epoch)
|
110
|
+
timeout_epoch = epoch + @ttl
|
111
|
+
death_row_nodes = RLP.decode(@db.get("deathrow:#{timeout_epoch}")) rescue []
|
112
|
+
|
113
|
+
@death_row.each do |node_key|
|
114
|
+
refcount, val = RLP.decode ref_get(node_key)
|
115
|
+
if refcount == ZERO_ENCODED
|
116
|
+
new_refcount = Utils.encode_int(DEATH_ROW_OFFSET + timeout_epoch)
|
117
|
+
ref_put node_key, RLP.encode([new_refcount, val])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
unless @death_row.empty?
|
122
|
+
logger.debug "#{@death_row.size} nodes marked for pruning during block #{timeout_epoch}"
|
123
|
+
end
|
124
|
+
|
125
|
+
death_row_nodes.concat @death_row
|
126
|
+
@death_row = []
|
127
|
+
@db.put "deathrow:#{timeout_epoch}", RLP.encode(death_row_nodes)
|
128
|
+
|
129
|
+
journal = RLP.decode(@db.get("journal:#{epoch}")) rescue []
|
130
|
+
journal.extend @journal
|
131
|
+
@journal = []
|
132
|
+
@db.put "journal:#{epoch}", RLP.encode(journal)
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Revert changes made during an epoch
|
137
|
+
#
|
138
|
+
def revert_refcount_changes(epoch)
|
139
|
+
timeout_epoch = epoch + @ttl
|
140
|
+
|
141
|
+
@db.delete("deathrow:#{timeout_epoch}") rescue nil
|
142
|
+
|
143
|
+
begin
|
144
|
+
journal = RLP.decode @db.get("journal:#{epoch}")
|
145
|
+
journal.reverse.each do |(new_refcount, key)|
|
146
|
+
node_object = RLP.decode ref_get(key)
|
147
|
+
ref_put key, RLP.encode([new_refcount, node_object[1]])
|
148
|
+
end
|
149
|
+
rescue
|
150
|
+
# do nothing
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def has_key?(k)
|
155
|
+
@db.has_key? ref_key(k)
|
156
|
+
end
|
157
|
+
alias :include? :has_key?
|
158
|
+
|
159
|
+
def put_temporarily(k, v)
|
160
|
+
inc_refcount k, v
|
161
|
+
dec_refcount k
|
162
|
+
end
|
163
|
+
|
164
|
+
def commit
|
165
|
+
@db.commit
|
166
|
+
end
|
167
|
+
|
168
|
+
def ref_get(k)
|
169
|
+
@db.get ref_key(k)
|
170
|
+
end
|
171
|
+
|
172
|
+
def ref_put(k, v)
|
173
|
+
@db.put ref_key(k), v
|
174
|
+
end
|
175
|
+
|
176
|
+
def ref_key(k)
|
177
|
+
"r:#{k}"
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
def logger
|
183
|
+
@logger ||= Logger.new 'eth.db.refcount'
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|