ruby-ethereum 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +40 -0
  4. data/lib/ethereum.rb +53 -0
  5. data/lib/ethereum/abi.rb +333 -0
  6. data/lib/ethereum/abi/contract_translator.rb +174 -0
  7. data/lib/ethereum/abi/type.rb +117 -0
  8. data/lib/ethereum/account.rb +72 -0
  9. data/lib/ethereum/address.rb +60 -0
  10. data/lib/ethereum/base_convert.rb +53 -0
  11. data/lib/ethereum/block.rb +1311 -0
  12. data/lib/ethereum/block_header.rb +211 -0
  13. data/lib/ethereum/bloom.rb +83 -0
  14. data/lib/ethereum/cached_block.rb +36 -0
  15. data/lib/ethereum/chain.rb +400 -0
  16. data/lib/ethereum/constant.rb +26 -0
  17. data/lib/ethereum/core_ext/array/safe_slice.rb +18 -0
  18. data/lib/ethereum/core_ext/module/lru_cache.rb +20 -0
  19. data/lib/ethereum/core_ext/numeric/denominations.rb +45 -0
  20. data/lib/ethereum/core_ext/object/truth.rb +47 -0
  21. data/lib/ethereum/db.rb +6 -0
  22. data/lib/ethereum/db/base_db.rb +9 -0
  23. data/lib/ethereum/db/ephem_db.rb +63 -0
  24. data/lib/ethereum/db/overlay_db.rb +72 -0
  25. data/lib/ethereum/db/refcount_db.rb +188 -0
  26. data/lib/ethereum/env.rb +64 -0
  27. data/lib/ethereum/ethash.rb +78 -0
  28. data/lib/ethereum/ethash_ruby.rb +38 -0
  29. data/lib/ethereum/ethash_ruby/cache.rb +47 -0
  30. data/lib/ethereum/ethash_ruby/hashimoto.rb +75 -0
  31. data/lib/ethereum/ethash_ruby/utils.rb +53 -0
  32. data/lib/ethereum/exceptions.rb +28 -0
  33. data/lib/ethereum/external_call.rb +173 -0
  34. data/lib/ethereum/fast_rlp.rb +81 -0
  35. data/lib/ethereum/fast_vm.rb +625 -0
  36. data/lib/ethereum/fast_vm/call_data.rb +44 -0
  37. data/lib/ethereum/fast_vm/message.rb +29 -0
  38. data/lib/ethereum/fast_vm/state.rb +25 -0
  39. data/lib/ethereum/ffi/openssl.rb +390 -0
  40. data/lib/ethereum/index.rb +97 -0
  41. data/lib/ethereum/log.rb +43 -0
  42. data/lib/ethereum/miner.rb +84 -0
  43. data/lib/ethereum/opcodes.rb +131 -0
  44. data/lib/ethereum/private_key.rb +92 -0
  45. data/lib/ethereum/pruning_trie.rb +28 -0
  46. data/lib/ethereum/public_key.rb +88 -0
  47. data/lib/ethereum/receipt.rb +53 -0
  48. data/lib/ethereum/secp256k1.rb +58 -0
  49. data/lib/ethereum/secure_trie.rb +49 -0
  50. data/lib/ethereum/sedes.rb +42 -0
  51. data/lib/ethereum/special_contract.rb +95 -0
  52. data/lib/ethereum/spv.rb +79 -0
  53. data/lib/ethereum/spv/proof.rb +31 -0
  54. data/lib/ethereum/spv/proof_constructor.rb +19 -0
  55. data/lib/ethereum/spv/proof_verifier.rb +24 -0
  56. data/lib/ethereum/tester.rb +14 -0
  57. data/lib/ethereum/tester/abi_contract.rb +65 -0
  58. data/lib/ethereum/tester/fixture.rb +31 -0
  59. data/lib/ethereum/tester/language.rb +30 -0
  60. data/lib/ethereum/tester/log_recorder.rb +13 -0
  61. data/lib/ethereum/tester/solidity_wrapper.rb +144 -0
  62. data/lib/ethereum/tester/state.rb +194 -0
  63. data/lib/ethereum/transaction.rb +196 -0
  64. data/lib/ethereum/transient_trie.rb +28 -0
  65. data/lib/ethereum/trie.rb +549 -0
  66. data/lib/ethereum/trie/nibble_key.rb +184 -0
  67. data/lib/ethereum/utils.rb +191 -0
  68. data/lib/ethereum/version.rb +5 -0
  69. data/lib/ethereum/vm.rb +606 -0
  70. data/lib/ethereum/vm/call_data.rb +40 -0
  71. data/lib/ethereum/vm/message.rb +30 -0
  72. data/lib/ethereum/vm/state.rb +25 -0
  73. 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
@@ -0,0 +1,6 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ require 'ethereum/db/base_db'
4
+ require 'ethereum/db/ephem_db'
5
+ require 'ethereum/db/overlay_db'
6
+ require 'ethereum/db/refcount_db'
@@ -0,0 +1,9 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ module Ethereum
4
+ module DB
5
+ class BaseDB
6
+ attr :db
7
+ end
8
+ end
9
+ end
@@ -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