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.
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