ciri 0.0.0 → 0.0.1

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +14 -0
  3. data/.rspec +2 -1
  4. data/.travis.yml +11 -4
  5. data/Gemfile.lock +3 -0
  6. data/README.md +44 -34
  7. data/Rakefile +47 -4
  8. data/ciri.gemspec +13 -12
  9. data/docker/Base +34 -0
  10. data/lib/ciri/actor.rb +223 -0
  11. data/lib/ciri/chain.rb +293 -0
  12. data/lib/ciri/chain/block.rb +47 -0
  13. data/lib/ciri/chain/header.rb +62 -0
  14. data/lib/ciri/chain/transaction.rb +145 -0
  15. data/lib/ciri/crypto.rb +58 -5
  16. data/lib/ciri/db/backend/memory.rb +68 -0
  17. data/lib/ciri/db/backend/rocks.rb +104 -0
  18. data/lib/ciri/db/backend/rocks_db.rb +278 -0
  19. data/lib/ciri/devp2p/peer.rb +10 -2
  20. data/lib/ciri/devp2p/protocol.rb +11 -3
  21. data/lib/ciri/devp2p/protocol_io.rb +6 -3
  22. data/lib/ciri/devp2p/rlpx.rb +1 -0
  23. data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +1 -1
  24. data/lib/ciri/devp2p/rlpx/frame_io.rb +1 -1
  25. data/lib/ciri/devp2p/rlpx/message.rb +4 -4
  26. data/lib/ciri/devp2p/server.rb +14 -13
  27. data/lib/ciri/eth.rb +33 -0
  28. data/lib/ciri/eth/peer.rb +64 -0
  29. data/lib/ciri/eth/protocol_manage.rb +122 -0
  30. data/lib/ciri/eth/protocol_messages.rb +158 -0
  31. data/lib/ciri/eth/synchronizer.rb +188 -0
  32. data/lib/ciri/ethash.rb +123 -0
  33. data/lib/ciri/evm.rb +140 -0
  34. data/lib/ciri/evm/account.rb +50 -0
  35. data/lib/ciri/evm/block_info.rb +31 -0
  36. data/lib/ciri/evm/forks/frontier.rb +183 -0
  37. data/lib/ciri/evm/instruction.rb +92 -0
  38. data/lib/ciri/evm/machine_state.rb +81 -0
  39. data/lib/ciri/evm/op.rb +536 -0
  40. data/lib/ciri/evm/serialize.rb +60 -0
  41. data/lib/ciri/evm/sub_state.rb +64 -0
  42. data/lib/ciri/evm/vm.rb +379 -0
  43. data/lib/ciri/forks.rb +38 -0
  44. data/lib/ciri/forks/frontier.rb +43 -0
  45. data/lib/ciri/key.rb +7 -1
  46. data/lib/ciri/pow.rb +95 -0
  47. data/lib/ciri/rlp.rb +3 -53
  48. data/lib/ciri/rlp/decode.rb +100 -40
  49. data/lib/ciri/rlp/encode.rb +95 -34
  50. data/lib/ciri/rlp/serializable.rb +61 -91
  51. data/lib/ciri/types/address.rb +70 -0
  52. data/lib/ciri/types/errors.rb +36 -0
  53. data/lib/ciri/utils.rb +45 -13
  54. data/lib/ciri/utils/lib_c.rb +46 -0
  55. data/lib/ciri/utils/logger.rb +99 -0
  56. data/lib/ciri/utils/number.rb +67 -0
  57. data/lib/ciri/version.rb +1 -1
  58. metadata +67 -7
  59. data/lib/ciri/devp2p/actor.rb +0 -224
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require_relative 'evm/op'
25
+ require_relative 'evm/vm'
26
+ require_relative 'evm/account'
27
+ require 'ciri/forks'
28
+
29
+ module Ciri
30
+ class EVM
31
+
32
+ BLOCK_REWARD = 3 * 10.pow(18) # 3 ether
33
+
34
+ attr_reader :state
35
+
36
+ def initialize(state:)
37
+ @state = state
38
+ end
39
+
40
+ # run block
41
+ def finalize_block(block)
42
+ # validate block
43
+ # transition
44
+ # apply_changes
45
+ end
46
+
47
+ def validate_block(block)
48
+ # valid ommers
49
+ # valid transactions(block.gas_used == transactions...gas)
50
+ # Reward miner, ommers(reward == block reward + ommers reward)
51
+ # apply changes
52
+ # verify state and block nonce
53
+ # 1. parent header root == trie(state[i]) 当前状态的 root 相等, 返回 state[i] otherwise state[0]
54
+ end
55
+
56
+ # transition block
57
+ # block -> new block(mining)
58
+ # return new_block and status change
59
+ def transition(block)
60
+ # execute transactions, we don't need to valid transactions, it should be done before evm(in Chain module).
61
+ block.transactions.each do |transaction|
62
+ execute_transaction(transaction, header: block.header)
63
+ end
64
+ # status transfer
65
+ # state[c].balance += mining reward
66
+ # ommers: state[u.c].balance += uncle reward
67
+ #
68
+ # block.nonce
69
+ # block.mix
70
+ # R[i].gas_used = gas_used(state[i - 1], block.transactions[i]) + R[i - 1].gas_used
71
+ # R[i].logs = logs(state[i - 1], block.transactions[i])
72
+ # R[i].z = z(state[i - 1], block.transactions[i])
73
+ end
74
+
75
+ # execute transaction
76
+ # @param t Transaction
77
+ # @param header Chain::Header
78
+ def execute_transaction(t, header: nil, block_info: nil, ignore_exception: false)
79
+ instruction = Instruction.new(
80
+ origin: t.sender,
81
+ price: t.gas_price,
82
+ sender: t.sender,
83
+ value: t.value,
84
+ header: header,
85
+ execute_depth: 0,
86
+ )
87
+
88
+ if t.contract_creation?
89
+ instruction.bytes_code = t.data
90
+ instruction.address = t.sender
91
+ else
92
+ if (account = find_account t.to)
93
+ instruction.bytes_code = account.code
94
+ instruction.address = account.address
95
+ end
96
+ instruction.data = t.data
97
+ end
98
+
99
+ @vm = VM.spawn(
100
+ state: state,
101
+ gas_limit: t.gas_limit,
102
+ instruction: instruction,
103
+ header: header,
104
+ block_info: block_info,
105
+ fork_config: Ciri::Forks.detect_fork(header: header, number: block_info&.number)
106
+ )
107
+
108
+ if t.contract_creation?
109
+ # contract creation
110
+ @vm.create_contract(value: instruction.value, init: instruction.bytes_code)
111
+ else
112
+ # transact ether
113
+ begin
114
+ @vm.transact(sender: t.sender, value: t.value, to: t.to)
115
+ rescue VM::VMError
116
+ raise unless ignore_exception
117
+ return nil
118
+ end
119
+ @vm.run(ignore_exception: ignore_exception)
120
+ end
121
+ nil
122
+ end
123
+
124
+ def logs_hash
125
+ return nil unless @vm
126
+ Utils.sha3(RLP.encode_simple(@vm.sub_state.log_series))
127
+ end
128
+
129
+ private
130
+
131
+ def account_dead?(address)
132
+ Account.account_dead?(state, address)
133
+ end
134
+
135
+ def find_account(address)
136
+ Account.find_account(state, address)
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require 'ciri/utils'
25
+
26
+ module Ciri
27
+ class EVM
28
+
29
+ Account = Struct.new(:address, :balance, :code, :nonce, :storage, keyword_init: true) do
30
+ # EMPTY(σ,a) ≡ σ[a]c =KEC􏰁()􏰂∧σ[a]n =0∧σ[a]b =0
31
+ def empty?
32
+ code == Utils::BLANK_SHA3 && nonce == 0 && balance == 0
33
+ end
34
+
35
+ def self.new_empty(address)
36
+ Account.new(address: address, balance: 0, nonce: 0, storage: {})
37
+ end
38
+
39
+ def self.find_account(state, address)
40
+ state[address.to_s] || new_empty(address.to_s)
41
+ end
42
+
43
+ def self.account_dead?(state, address)
44
+ account = state[address.to_s]
45
+ account.nil? || account.empty?
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ module Ciri
25
+ class EVM
26
+
27
+ # Block Info
28
+ BlockInfo = Struct.new(:coinbase, :difficulty, :gas_limit, :number, :timestamp, keyword_init: true)
29
+
30
+ end
31
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require 'ciri/evm/op'
25
+
26
+ module Ciri
27
+ class EVM
28
+ module Forks
29
+ module Frontier
30
+
31
+ module Cost
32
+ # fee schedule, start with G
33
+ G_ZERO = 0
34
+ G_BASE = 2
35
+ G_VERYLOW = 3
36
+ G_LOW = 5
37
+ G_MID = 8
38
+ G_HIGH = 10
39
+ G_EXTCODE = 700
40
+ G_BALANCE = 400
41
+ G_SLOAD = 50
42
+ G_JUMPDEST = 1
43
+ G_SSET = 20000
44
+ G_RESET = 5000
45
+ R_SCLEAR = 15000
46
+ R_SELFDESTRUCT = 24000
47
+ G_SELFDESTRUCT = 0
48
+ G_CREATE = 32000
49
+ G_CODEDEPOSIT = 200
50
+ G_CALL = 700
51
+ G_CALLVALUE = 9000
52
+ G_CALLSTIPEND = 2300
53
+ G_NEWACCOUNT = 25000
54
+ G_EXP = 10
55
+ G_EXPBYTE = 10
56
+ G_MEMORY = 3
57
+ G_TXCREATE = 32000
58
+ G_TXDATAZERO = 4
59
+ G_TXDATANONZERO = 68
60
+ G_TRANSACTION = 21000
61
+ G_LOG = 375
62
+ G_LOGDATA = 8
63
+ G_TOPIC = 375
64
+ G_SHA3 = 30
65
+ G_SHA3WORD = 6
66
+ G_COPY = 3
67
+ G_BLOCKHASH = 20
68
+ G_QUADDIVISOR = 100
69
+
70
+ # operation code by group, for later calculation
71
+ W_ZERO = [OP::STOP, OP::RETURN, OP::REVERT]
72
+ W_BASE = [OP::ADDRESS, OP::ORIGIN, OP::CALLER, OP::CALLVALUE, OP::CALLDATASIZE, OP::CODESIZE, OP::GASPRICE,
73
+ OP::COINBASE, OP::TIMESTAMP, OP::NUMBER, OP::DIFFICULTY, OP::GASLIMIT, OP::RETURNDATASIZE,
74
+ OP::POP, OP::PC, OP::MSIZE, OP::GAS]
75
+ W_VERYLOW = [OP::ADD, OP::SUB, OP::NOT, OP::LT, OP::GT, OP::SLT, OP::SGT, OP::EQ, OP::ISZERO, OP::AND, OP::OR,
76
+ OP::XOR, OP::BYTE, OP::CALLDATALOAD, OP::MLOAD, OP::MSTORE, OP::MSTORE8,
77
+ *(1..32).map {|i| OP.get(OP::PUSH1 + i - 1).code}, # push1 - push32
78
+ *(1..16).map {|i| OP.get(OP::DUP1 + i - 1).code}, # dup1 - dup16
79
+ *(1..16).map {|i| OP.get(OP::SWAP1 + i - 1).code}] # swap1 - swap16
80
+ W_LOW = [OP::MUL, OP::DIV, OP::SDIV, OP::MOD, OP::SMOD, OP::SIGNEXTEND]
81
+ W_MID = [OP::ADDMOD, OP::MULMOD, OP::JUMP]
82
+ W_HIGH = [OP::JUMPI]
83
+ W_EXTCODE = [OP::EXTCODESIZE]
84
+
85
+
86
+ class << self
87
+ # C(σ,μ,I)
88
+ # calculate cost of current operation
89
+ def cost_of_operation(vm)
90
+ ms = vm.machine_state
91
+ instruction = vm.instruction
92
+ w = instruction.get_op(ms.pc)
93
+ if w == OP::SSTORE
94
+ cost_of_sstore(vm)
95
+ elsif w == OP::EXP && ms.get_stack(1, Integer) == 0
96
+ G_EXP
97
+ elsif w == OP::EXP && (x = ms.get_stack(1, Integer)) > 0
98
+ G_EXP + G_EXPBYTE * Utils.ceil_div(x.bit_length, 8)
99
+ elsif w == OP::CALLDATACOPY || w == OP::CODECOPY || w == OP::RETURNDATACOPY
100
+ G_VERYLOW + G_COPY * Utils.ceil_div(ms.get_stack(2, Integer), 32)
101
+ elsif w == OP::EXTCODECOPY
102
+ G_EXTCODE + G_COPY * Utils.ceil_div(ms.get_stack(3, Integer), 32)
103
+ elsif (OP::LOG0..OP::LOG4).include? w
104
+ G_LOG + G_LOGDATA * ms.get_stack(1, Integer) + (w - OP::LOG0) * G_TOPIC
105
+ elsif w == OP::CALL || w == OP::CALLCODE || w == OP::DELEGATECALL
106
+ 1# cost_of_call(state, ms)
107
+ elsif w == OP::SELFDESTRUCT
108
+ cost_of_self_destruct(vm)
109
+ elsif w == OP::CREATE
110
+ G_CREATE
111
+ elsif w == OP::SHA3
112
+ G_SHA3 + G_SHA3WORD * Utils.ceil_div(ms.get_stack(1, Integer), 32)
113
+ elsif w == OP::JUMPDEST
114
+ G_JUMPDEST
115
+ elsif w == OP::SLOAD
116
+ G_SLOAD
117
+ elsif W_ZERO.include? w
118
+ G_ZERO
119
+ elsif W_BASE.include? w
120
+ G_BASE
121
+ elsif W_VERYLOW.include? w
122
+ G_VERYLOW
123
+ elsif W_LOW.include? w
124
+ G_LOW
125
+ elsif W_MID.include? w
126
+ G_MID
127
+ elsif W_HIGH.include? w
128
+ G_HIGH
129
+ elsif W_EXTCODE.include? w
130
+ G_EXTCODE
131
+ elsif w == OP::BALANCE
132
+ G_BALANCE
133
+ elsif w == OP::BLOCKHASH
134
+ G_BLOCKHASH
135
+ else
136
+ raise "can't compute cost for unknown op #{w}"
137
+ end
138
+ end
139
+
140
+ def cost_of_memory(i)
141
+ G_MEMORY * i + (i ** 2) / 512
142
+ end
143
+
144
+ def intrinsic_gas_of_transaction(t)
145
+ gas = (t.data.each_byte || '').reduce(0) {|sum, i| sum + i.zero? ? G_TXDATAZERO : G_TXDATANONZERO}
146
+ gas + (t.to.empty? ? G_TXCREATE : 0) + G_TRANSACTION
147
+ end
148
+
149
+ private
150
+
151
+ def cost_of_self_destruct(vm)
152
+ G_SELFDESTRUCT
153
+ end
154
+
155
+ def cost_of_call
156
+
157
+ end
158
+
159
+ def cost_of_sstore(vm)
160
+ ms = vm.machine_state
161
+ instruction = vm.instruction
162
+
163
+ key = ms.stack[0]
164
+ value = ms.stack[1]
165
+ account = vm.find_account instruction.address
166
+
167
+ value_exists = !Ciri::Utils.blank_binary?(value)
168
+ has_key = account && account.storage[key]
169
+
170
+ if value_exists && !has_key
171
+ G_SSET
172
+ else
173
+ G_RESET
174
+ end
175
+ end
176
+
177
+ end
178
+ end
179
+
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ module Ciri
25
+ class EVM
26
+
27
+ # represent instruction
28
+ Instruction = Struct.new(:address, :origin, :price, :data, :sender, :value, :bytes_code, :header, :execute_depth,
29
+ keyword_init: true) do
30
+
31
+ def initialize(*args)
32
+ super
33
+ self.data ||= ''.b
34
+ self.value ||= 0
35
+ self.bytes_code ||= ''.b
36
+ self.execute_depth ||= 0
37
+ end
38
+
39
+ def get_op(pos)
40
+ return OP::INVALID if pos >= (bytes_code || ''.b).size
41
+ bytes_code[pos].ord
42
+ end
43
+
44
+ # get data from instruction
45
+ def get_code(pos, size = 1)
46
+ if size > 0 && pos < bytes_code.size && pos + size - 1 < bytes_code.size
47
+ bytes_code[pos..(pos + size - 1)]
48
+ else
49
+ "\x00".b * size
50
+ end
51
+ end
52
+
53
+ def get_data(pos, size)
54
+ if pos < data.size && size > 0
55
+ data[pos..(pos + size - 1)].ljust(size, "\x00".b)
56
+ else
57
+ "\x00".b * size
58
+ end
59
+ end
60
+
61
+ # valid destinations of bytes_code
62
+ def destinations
63
+ @destinations ||= destinations_by_index(bytes_code, 0)
64
+ end
65
+
66
+ def next_valid_instruction_pos(pos, op_code)
67
+ if (OP::PUSH1..OP::PUSH32).include?(op_code)
68
+ pos + op_code - OP::PUSH1 + 2
69
+ else
70
+ pos + 1
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def destinations_by_index(bytes_code, i)
77
+ destinations = []
78
+ loop do
79
+ if i > bytes_code.size
80
+ break
81
+ elsif bytes_code[i] == OP::JUMPDEST
82
+ destinations << i
83
+ end
84
+ i = next_valid_instruction_pos(i, bytes_code[i])
85
+ end
86
+ destinations
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+ end