ciri 0.0.1 → 0.0.2
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 +4 -4
 - data/Gemfile.lock +8 -3
 - data/README.md +5 -0
 - data/Rakefile +24 -2
 - data/ciri-rlp/.gitignore +11 -0
 - data/ciri-rlp/.rspec +3 -0
 - data/ciri-rlp/.travis.yml +5 -0
 - data/ciri-rlp/CODE_OF_CONDUCT.md +74 -0
 - data/ciri-rlp/Gemfile +6 -0
 - data/ciri-rlp/Gemfile.lock +39 -0
 - data/ciri-rlp/LICENSE.txt +21 -0
 - data/ciri-rlp/README.md +98 -0
 - data/ciri-rlp/Rakefile +6 -0
 - data/ciri-rlp/bin/console +14 -0
 - data/ciri-rlp/bin/setup +8 -0
 - data/ciri-rlp/ciri-rlp.gemspec +28 -0
 - data/{lib → ciri-rlp/lib}/ciri/rlp.rb +2 -2
 - data/ciri-rlp/lib/ciri/rlp/decode.rb +144 -0
 - data/ciri-rlp/lib/ciri/rlp/encode.rb +140 -0
 - data/ciri-rlp/lib/ciri/rlp/serializable.rb +241 -0
 - data/ciri-rlp/lib/ciri/rlp/version.rb +5 -0
 - data/ciri-rlp/spec/ciri/fixture_spec.rb +95 -0
 - data/ciri-rlp/spec/ciri/rlp/decode_spec.rb +68 -0
 - data/ciri-rlp/spec/ciri/rlp/encode_spec.rb +72 -0
 - data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +147 -0
 - data/ciri-rlp/spec/ciri/rlp_spec.rb +5 -0
 - data/ciri-rlp/spec/spec_helper.rb +14 -0
 - data/ciri-utils/.gitignore +11 -0
 - data/ciri-utils/.rspec +3 -0
 - data/ciri-utils/.travis.yml +5 -0
 - data/ciri-utils/CODE_OF_CONDUCT.md +74 -0
 - data/ciri-utils/Gemfile +6 -0
 - data/ciri-utils/Gemfile.lock +37 -0
 - data/ciri-utils/LICENSE.txt +21 -0
 - data/ciri-utils/README.md +61 -0
 - data/ciri-utils/Rakefile +6 -0
 - data/ciri-utils/bin/console +14 -0
 - data/ciri-utils/bin/setup +8 -0
 - data/ciri-utils/ciri-utils.gemspec +28 -0
 - data/{lib → ciri-utils/lib}/ciri/utils.rb +9 -33
 - data/{lib → ciri-utils/lib}/ciri/utils/logger.rb +0 -0
 - data/{lib → ciri-utils/lib}/ciri/utils/number.rb +15 -12
 - data/ciri-utils/lib/ciri/utils/version.rb +5 -0
 - data/ciri-utils/spec/ciri/utils_spec.rb +5 -0
 - data/ciri-utils/spec/spec_helper.rb +14 -0
 - data/ciri.gemspec +6 -3
 - data/lib/ciri/bloom_filter.rb +83 -0
 - data/lib/ciri/chain.rb +67 -130
 - data/lib/ciri/chain/header.rb +2 -2
 - data/lib/ciri/chain/header_chain.rb +136 -0
 - data/lib/ciri/chain/transaction.rb +1 -1
 - data/lib/ciri/crypto.rb +2 -2
 - data/lib/ciri/db/account_db.rb +145 -0
 - data/lib/ciri/db/backend/memory.rb +24 -1
 - data/lib/ciri/devp2p/peer.rb +1 -1
 - data/lib/ciri/devp2p/rlpx/connection.rb +5 -5
 - data/lib/ciri/eth/peer.rb +3 -3
 - data/lib/ciri/eth/protocol_manage.rb +3 -3
 - data/lib/ciri/eth/protocol_messages.rb +27 -26
 - data/lib/ciri/ethash.rb +18 -3
 - data/lib/ciri/evm.rb +101 -56
 - data/lib/ciri/{utils/lib_c.rb → evm/errors.rb} +28 -18
 - data/lib/ciri/evm/instruction.rb +3 -1
 - data/lib/ciri/evm/{serialize.rb → log_entry.rb} +9 -27
 - data/lib/ciri/evm/machine_state.rb +21 -2
 - data/lib/ciri/evm/op.rb +19 -16
 - data/lib/ciri/evm/state.rb +61 -0
 - data/lib/ciri/evm/vm.rb +78 -102
 - data/lib/ciri/forks.rb +1 -4
 - data/lib/ciri/forks/base.rb +55 -0
 - data/lib/ciri/forks/frontier.rb +37 -10
 - data/lib/ciri/forks/frontier/cost.rb +186 -0
 - data/lib/ciri/key.rb +1 -1
 - data/lib/ciri/pow.rb +1 -1
 - data/lib/ciri/rlp/decode.rb +6 -3
 - data/lib/ciri/rlp/encode.rb +10 -10
 - data/lib/ciri/rlp/serializable.rb +12 -9
 - data/lib/ciri/serialize.rb +58 -0
 - data/lib/ciri/trie.rb +362 -0
 - data/lib/ciri/trie/nibbles.rb +97 -0
 - data/lib/ciri/trie/nodes.rb +187 -0
 - data/lib/ciri/{evm → types}/account.rb +20 -13
 - data/lib/ciri/types/address.rb +16 -11
 - data/lib/ciri/types/number.rb +73 -0
 - data/lib/ciri/types/receipt.rb +57 -0
 - data/lib/ciri/version.rb +1 -1
 - metadata +82 -19
 - data/lib/ciri/evm/forks/frontier.rb +0 -183
 
| 
         @@ -21,25 +21,35 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
            require 'ffi'
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
24 
     | 
    
         
             
            module Ciri
         
     | 
| 
       27 
     | 
    
         
            -
               
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                 
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
              class EVM
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                class Error < StandardError
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                class InvalidTransition < Error
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                class InvalidTransaction < Error
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                # VM errors
         
     | 
| 
      
 37 
     | 
    
         
            +
                class VMError < Error
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                class InvalidOpCodeError < VMError
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                class GasNotEnoughError < VMError
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                class StackError < VMError
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                class InvalidJumpError < VMError
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                class ReturnError < VMError
         
     | 
| 
       43 
53 
     | 
    
         
             
                end
         
     | 
| 
       44 
54 
     | 
    
         | 
| 
       45 
55 
     | 
    
         
             
              end
         
     | 
    
        data/lib/ciri/evm/instruction.rb
    CHANGED
    
    
| 
         @@ -21,40 +21,22 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
            require 'ciri/rlp'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require 'ciri/utils'
         
     | 
| 
       24 
26 
     | 
    
         
             
            require 'ciri/types/address'
         
     | 
| 
      
 27 
     | 
    
         
            +
            require 'ciri/types/number'
         
     | 
| 
       25 
28 
     | 
    
         | 
| 
       26 
29 
     | 
    
         
             
            module Ciri
         
     | 
| 
       27 
30 
     | 
    
         
             
              class EVM
         
     | 
| 
       28 
     | 
    
         
            -
                module Serialize
         
     | 
| 
       29 
31 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
                class LogEntry
         
     | 
| 
      
 33 
     | 
    
         
            +
                  include RLP::Serializable
         
     | 
| 
      
 34 
     | 
    
         
            +
                  schema [{address: Types::Address}, {topics: [Types::Int32]}, :data]
         
     | 
| 
       31 
35 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                  def  
     | 
| 
       33 
     | 
    
         
            -
                     
     | 
| 
       34 
     | 
    
         
            -
                    when Integer
         
     | 
| 
       35 
     | 
    
         
            -
                      Utils.big_endian_encode(item)
         
     | 
| 
       36 
     | 
    
         
            -
                    when Types::Address
         
     | 
| 
       37 
     | 
    
         
            -
                      item.to_s
         
     | 
| 
       38 
     | 
    
         
            -
                    else
         
     | 
| 
       39 
     | 
    
         
            -
                      item
         
     | 
| 
       40 
     | 
    
         
            -
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  def to_blooms
         
     | 
| 
      
 37 
     | 
    
         
            +
                    [address.to_s, *topics.map {|t| Utils.big_endian_encode(t, size: 32)}]
         
     | 
| 
       41 
38 
     | 
    
         
             
                  end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                  def deserialize(type, item)
         
     | 
| 
       44 
     | 
    
         
            -
                    if type == Integer && !item.is_a?(Integer)
         
     | 
| 
       45 
     | 
    
         
            -
                      Utils.big_endian_decode(item.to_s)
         
     | 
| 
       46 
     | 
    
         
            -
                    elsif type == Types::Address && !item.is_a?(Types::Address)
         
     | 
| 
       47 
     | 
    
         
            -
                      # check if address represent in Integer
         
     | 
| 
       48 
     | 
    
         
            -
                      item = Utils.big_endian_encode(item) if item.is_a?(Integer)
         
     | 
| 
       49 
     | 
    
         
            -
                      Types::Address.new(item.size >= 20 ? item[-20..-1] : ''.b)
         
     | 
| 
       50 
     | 
    
         
            -
                    elsif type.nil?
         
     | 
| 
       51 
     | 
    
         
            -
                      # get serialized word
         
     | 
| 
       52 
     | 
    
         
            -
                      serialize(item).rjust(32, "\x00".b)
         
     | 
| 
       53 
     | 
    
         
            -
                    else
         
     | 
| 
       54 
     | 
    
         
            -
                      item
         
     | 
| 
       55 
     | 
    
         
            -
                    end
         
     | 
| 
       56 
     | 
    
         
            -
                  end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
39 
     | 
    
         
             
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
       59 
41 
     | 
    
         
             
              end
         
     | 
| 
       60 
42 
     | 
    
         
             
            end
         
     | 
| 
         @@ -21,13 +21,32 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
            require 'ciri/serialize'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require 'ciri/evm/errors'
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
            module Ciri
         
     | 
| 
       27 
28 
     | 
    
         
             
              class EVM
         
     | 
| 
       28 
29 
     | 
    
         | 
| 
       29 
30 
     | 
    
         
             
                # represent current vm status, include stack, memory..
         
     | 
| 
       30 
     | 
    
         
            -
                MachineState 
     | 
| 
      
 31 
     | 
    
         
            +
                class MachineState
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  attr_reader :remain_gas, :memory, :stack
         
     | 
| 
      
 34 
     | 
    
         
            +
                  attr_accessor :pc, :output, :memory_item
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def initialize(remain_gas:, pc:, memory:, memory_item:, stack:, output: ''.b)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    raise ArgumentError.new("remain_gas must more than 0") if remain_gas < 0
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @remain_gas = remain_gas
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @pc = pc
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @memory = memory
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @memory_item = memory_item
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @stack = stack
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @output = output
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def consume_gas(gas)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    raise GasNotEnoughError.new("can't consume gas to negative, remain_gas: #{remain_gas}, consumed: #{gas}") if gas > remain_gas
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @remain_gas -= gas
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
       31 
50 
     | 
    
         | 
| 
       32 
51 
     | 
    
         
             
                  # fetch a list of items from stack
         
     | 
| 
       33 
52 
     | 
    
         
             
                  def pop_list(count, type = nil)
         
     | 
    
        data/lib/ciri/evm/op.rb
    CHANGED
    
    | 
         @@ -24,7 +24,6 @@ 
     | 
|
| 
       24 
24 
     | 
    
         
             
            require 'ciri/utils'
         
     | 
| 
       25 
25 
     | 
    
         
             
            require 'ciri/utils/number'
         
     | 
| 
       26 
26 
     | 
    
         
             
            require 'ciri/types/address'
         
     | 
| 
       27 
     | 
    
         
            -
            require_relative 'serialize'
         
     | 
| 
       28 
27 
     | 
    
         | 
| 
       29 
28 
     | 
    
         
             
            module Ciri
         
     | 
| 
       30 
29 
     | 
    
         
             
              class EVM
         
     | 
| 
         @@ -267,7 +266,7 @@ module Ciri 
     | 
|
| 
       267 
266 
     | 
    
         | 
| 
       268 
267 
     | 
    
         
             
                  def_op :EXTCODESIZE, 0x3b, 0, 1 do |vm|
         
     | 
| 
       269 
268 
     | 
    
         
             
                    address = vm.pop(Address)
         
     | 
| 
       270 
     | 
    
         
            -
                    code_size = vm. 
     | 
| 
      
 269 
     | 
    
         
            +
                    code_size = vm.get_account_code(address).size
         
     | 
| 
       271 
270 
     | 
    
         
             
                    vm.push code_size
         
     | 
| 
       272 
271 
     | 
    
         
             
                  end
         
     | 
| 
       273 
272 
     | 
    
         | 
| 
         @@ -275,8 +274,7 @@ module Ciri 
     | 
|
| 
       275 
274 
     | 
    
         
             
                    address = vm.pop(Address)
         
     | 
| 
       276 
275 
     | 
    
         
             
                    mem_pos, data_pos, size = vm.pop_list(3, Integer)
         
     | 
| 
       277 
276 
     | 
    
         | 
| 
       278 
     | 
    
         
            -
                     
     | 
| 
       279 
     | 
    
         
            -
                    code = account.code || ''.b
         
     | 
| 
      
 277 
     | 
    
         
            +
                    code = vm.get_account_code(address)
         
     | 
| 
       280 
278 
     | 
    
         
             
                    data_end_pos = data_pos + size - 1
         
     | 
| 
       281 
279 
     | 
    
         
             
                    data = if data_pos >= code.size
         
     | 
| 
       282 
280 
     | 
    
         
             
                             ''.b
         
     | 
| 
         @@ -340,13 +338,13 @@ module Ciri 
     | 
|
| 
       340 
338 
     | 
    
         
             
                  end
         
     | 
| 
       341 
339 
     | 
    
         | 
| 
       342 
340 
     | 
    
         
             
                  def_op :SLOAD, 0x54, 1, 1 do |vm|
         
     | 
| 
       343 
     | 
    
         
            -
                    key = vm.pop
         
     | 
| 
      
 341 
     | 
    
         
            +
                    key = vm.pop(Integer)
         
     | 
| 
       344 
342 
     | 
    
         
             
                    vm.push vm.fetch(vm.instruction.address, key)
         
     | 
| 
       345 
343 
     | 
    
         
             
                  end
         
     | 
| 
       346 
344 
     | 
    
         | 
| 
       347 
345 
     | 
    
         
             
                  def_op :SSTORE, 0x55, 2, 0 do |vm|
         
     | 
| 
       348 
     | 
    
         
            -
                    key = vm.pop
         
     | 
| 
       349 
     | 
    
         
            -
                    value = vm.pop
         
     | 
| 
      
 346 
     | 
    
         
            +
                    key = vm.pop(Integer)
         
     | 
| 
      
 347 
     | 
    
         
            +
                    value = vm.pop(Integer)
         
     | 
| 
       350 
348 
     | 
    
         | 
| 
       351 
349 
     | 
    
         
             
                    vm.store(vm.instruction.address, key, value)
         
     | 
| 
       352 
350 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -374,7 +372,7 @@ module Ciri 
     | 
|
| 
       374 
372 
     | 
    
         
             
                  end
         
     | 
| 
       375 
373 
     | 
    
         | 
| 
       376 
374 
     | 
    
         
             
                  def_op :GAS, 0x5a, 0, 1 do |vm|
         
     | 
| 
       377 
     | 
    
         
            -
                    vm.push vm.machine_state. 
     | 
| 
      
 375 
     | 
    
         
            +
                    vm.push vm.machine_state.remain_gas
         
     | 
| 
       378 
376 
     | 
    
         
             
                  end
         
     | 
| 
       379 
377 
     | 
    
         | 
| 
       380 
378 
     | 
    
         
             
                  def_op :JUMPDEST, 0x5b, 0, 0
         
     | 
| 
         @@ -421,7 +419,7 @@ module Ciri 
     | 
|
| 
       421 
419 
     | 
    
         
             
                        pos, size = vm.pop_list(2, Integer)
         
     | 
| 
       422 
420 
     | 
    
         
             
                        log_data = vm.memory_fetch(pos, size)
         
     | 
| 
       423 
421 
     | 
    
         
             
                        vm.extend_memory(pos, size)
         
     | 
| 
       424 
     | 
    
         
            -
                        topics = vm.pop_list(i)
         
     | 
| 
      
 422 
     | 
    
         
            +
                        topics = vm.pop_list(i, Integer)
         
     | 
| 
       425 
423 
     | 
    
         
             
                        vm.add_log_entry(topics, log_data)
         
     | 
| 
       426 
424 
     | 
    
         
             
                      end
         
     | 
| 
       427 
425 
     | 
    
         
             
                    end.call(i))
         
     | 
| 
         @@ -435,7 +433,7 @@ module Ciri 
     | 
|
| 
       435 
433 
     | 
    
         
             
                    init = vm.memory_fetch(mem_pos, size)
         
     | 
| 
       436 
434 
     | 
    
         
             
                    vm.extend_memory(mem_pos, size)
         
     | 
| 
       437 
435 
     | 
    
         | 
| 
       438 
     | 
    
         
            -
                    contract_address = vm.create_contract(value: value, init: init)
         
     | 
| 
      
 436 
     | 
    
         
            +
                    contract_address, _ = vm.create_contract(value: value, init: init)
         
     | 
| 
       439 
437 
     | 
    
         
             
                    vm.push contract_address
         
     | 
| 
       440 
438 
     | 
    
         
             
                  end
         
     | 
| 
       441 
439 
     | 
    
         | 
| 
         @@ -504,7 +502,13 @@ module Ciri 
     | 
|
| 
       504 
502 
     | 
    
         
             
                  end
         
     | 
| 
       505 
503 
     | 
    
         | 
| 
       506 
504 
     | 
    
         
             
                  STATICCALL = 0xfa
         
     | 
| 
       507 
     | 
    
         
            -
             
     | 
| 
      
 505 
     | 
    
         
            +
             
     | 
| 
      
 506 
     | 
    
         
            +
                  # TODO REVERT need to be implement in forks
         
     | 
| 
      
 507 
     | 
    
         
            +
                  def_op :REVERT, -0xfd, 2, 0 do |vm|
         
     | 
| 
      
 508 
     | 
    
         
            +
                    index, size = vm.pop_list(2, Integer)
         
     | 
| 
      
 509 
     | 
    
         
            +
                    vm.output = vm.memory_fetch(index, size)
         
     | 
| 
      
 510 
     | 
    
         
            +
                    vm.extend_memory(index, size)
         
     | 
| 
      
 511 
     | 
    
         
            +
                  end
         
     | 
| 
       508 
512 
     | 
    
         | 
| 
       509 
513 
     | 
    
         
             
                  def_op :INVALID, 0xfe, 0, 0 do |vm|
         
     | 
| 
       510 
514 
     | 
    
         
             
                    raise 'should not invoke INVALID'
         
     | 
| 
         @@ -514,7 +518,6 @@ module Ciri 
     | 
|
| 
       514 
518 
     | 
    
         
             
                    refund_address = vm.pop(Address)
         
     | 
| 
       515 
519 
     | 
    
         
             
                    refund_account = vm.find_account(refund_address)
         
     | 
| 
       516 
520 
     | 
    
         | 
| 
       517 
     | 
    
         
            -
                    vm.sub_state.suicide_accounts << vm.instruction.address
         
     | 
| 
       518 
521 
     | 
    
         
             
                    contract_account = vm.find_account vm.instruction.address
         
     | 
| 
       519 
522 
     | 
    
         | 
| 
       520 
523 
     | 
    
         
             
                    if refund_address != vm.instruction.address
         
     | 
| 
         @@ -523,12 +526,12 @@ module Ciri 
     | 
|
| 
       523 
526 
     | 
    
         | 
| 
       524 
527 
     | 
    
         
             
                    contract_account.balance = 0
         
     | 
| 
       525 
528 
     | 
    
         | 
| 
       526 
     | 
    
         
            -
                    vm. 
     | 
| 
       527 
     | 
    
         
            -
                    vm. 
     | 
| 
      
 529 
     | 
    
         
            +
                    vm.state.set_balance(refund_address, refund_account.balance)
         
     | 
| 
      
 530 
     | 
    
         
            +
                    vm.state.set_balance(vm.instruction.address, contract_account.balance)
         
     | 
| 
       528 
531 
     | 
    
         | 
| 
       529 
532 
     | 
    
         
             
                    # register changed accounts
         
     | 
| 
       530 
     | 
    
         
            -
                    vm.add_refund_account( 
     | 
| 
       531 
     | 
    
         
            -
                    vm.add_suicide_account( 
     | 
| 
      
 533 
     | 
    
         
            +
                    vm.add_refund_account(refund_address)
         
     | 
| 
      
 534 
     | 
    
         
            +
                    vm.add_suicide_account(vm.instruction.address)
         
     | 
| 
       532 
535 
     | 
    
         
             
                  end
         
     | 
| 
       533 
536 
     | 
    
         | 
| 
       534 
537 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,61 @@ 
     | 
|
| 
      
 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 'forwardable'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require 'ciri/db/account_db'
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            module Ciri
         
     | 
| 
      
 28 
     | 
    
         
            +
              class EVM
         
     | 
| 
      
 29 
     | 
    
         
            +
                class State
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  extend Forwardable
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def_delegators :@account_db, :set_nonce, :increment_nonce, :set_balance, :add_balance, :touch_account,
         
     | 
| 
      
 34 
     | 
    
         
            +
                                 :find_account, :delete_account, :account_dead?, :store, :fetch, :set_account_code, :get_account_code
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def initialize(db, state_root: nil)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @db = db
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @account_db = DB::AccountDB.new(db, root_hash: state_root)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def snapshot
         
     | 
| 
      
 42 
     | 
    
         
            +
                    [state_root, @db.dup]
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def revert(snapshot)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    state_root, db = snapshot
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @db = db
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @account_db = DB::AccountDB.new(db, root_hash: state_root)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def commit(snapshot)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    true
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def state_root
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @account_db.root_hash
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/ciri/evm/vm.rb
    CHANGED
    
    | 
         @@ -21,11 +21,13 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
            require 'ciri/utils/logger'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require_relative 'errors'
         
     | 
| 
       24 
26 
     | 
    
         
             
            require_relative 'machine_state'
         
     | 
| 
       25 
27 
     | 
    
         
             
            require_relative 'instruction'
         
     | 
| 
       26 
28 
     | 
    
         
             
            require_relative 'sub_state'
         
     | 
| 
       27 
29 
     | 
    
         
             
            require_relative 'block_info'
         
     | 
| 
       28 
     | 
    
         
            -
            require_relative ' 
     | 
| 
      
 30 
     | 
    
         
            +
            require_relative 'log_entry'
         
     | 
| 
       29 
31 
     | 
    
         | 
| 
       30 
32 
     | 
    
         
             
            module Ciri
         
     | 
| 
       31 
33 
     | 
    
         
             
              class EVM
         
     | 
| 
         @@ -40,25 +42,12 @@ module Ciri 
     | 
|
| 
       40 
42 
     | 
    
         
             
                # other logic of EVM (include transaction logic) in EVM module.
         
     | 
| 
       41 
43 
     | 
    
         
             
                class VM
         
     | 
| 
       42 
44 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                  class VMError < StandardError
         
     | 
| 
       44 
     | 
    
         
            -
                  end
         
     | 
| 
       45 
     | 
    
         
            -
                  class InvalidOpCodeError < VMError
         
     | 
| 
       46 
     | 
    
         
            -
                  end
         
     | 
| 
       47 
     | 
    
         
            -
                  class GasNotEnoughError < VMError
         
     | 
| 
       48 
     | 
    
         
            -
                  end
         
     | 
| 
       49 
     | 
    
         
            -
                  class StackError < VMError
         
     | 
| 
       50 
     | 
    
         
            -
                  end
         
     | 
| 
       51 
     | 
    
         
            -
                  class InvalidJumpError < VMError
         
     | 
| 
       52 
     | 
    
         
            -
                  end
         
     | 
| 
       53 
     | 
    
         
            -
                  class ReturnError < VMError
         
     | 
| 
       54 
     | 
    
         
            -
                  end
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
45 
     | 
    
         
             
                  class << self
         
     | 
| 
       57 
46 
     | 
    
         
             
                    # this method provide a simpler interface to create VM and execute code
         
     | 
| 
       58 
47 
     | 
    
         
             
                    # VM.spawn(...) == VM.new(...)
         
     | 
| 
       59 
48 
     | 
    
         
             
                    # @return VM
         
     | 
| 
       60 
     | 
    
         
            -
                    def spawn(state:, gas_limit:, header: nil, block_info: nil, instruction 
     | 
| 
       61 
     | 
    
         
            -
                      ms = MachineState.new( 
     | 
| 
      
 49 
     | 
    
         
            +
                    def spawn(state:, gas_limit:, header: nil, block_info: nil, instruction: EVM::Instruction.new, fork_config:)
         
     | 
| 
      
 50 
     | 
    
         
            +
                      ms = MachineState.new(remain_gas: gas_limit, pc: 0, stack: [], memory: "\x00".b * 256, memory_item: 0)
         
     | 
| 
       62 
51 
     | 
    
         | 
| 
       63 
52 
     | 
    
         
             
                      block_info = block_info || header && BlockInfo.new(
         
     | 
| 
       64 
53 
     | 
    
         
             
                        coinbase: header.beneficiary,
         
     | 
| 
         @@ -84,17 +73,18 @@ module Ciri 
     | 
|
| 
       84 
73 
     | 
    
         | 
| 
       85 
74 
     | 
    
         
             
                  # helper methods
         
     | 
| 
       86 
75 
     | 
    
         
             
                  include Utils::Logger
         
     | 
| 
       87 
     | 
    
         
            -
                  include Serialize
         
     | 
| 
       88 
76 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
                  def_delegators :@machine_state, :stack, :pc, :pop, :push, :pop_list, :get_stack,
         
     | 
| 
       90 
     | 
    
         
            -
                                 : 
     | 
| 
      
 77 
     | 
    
         
            +
                  def_delegators :@machine_state, :stack, :pc, :pop, :push, :pop_list, :get_stack, :memory_item, :memory_item=,
         
     | 
| 
      
 78 
     | 
    
         
            +
                                 :memory_store, :memory_fetch, :extend_memory, :remain_gas, :consume_gas
         
     | 
| 
       91 
79 
     | 
    
         
             
                  def_delegators :@instruction, :get_op, :get_code, :next_valid_instruction_pos, :get_data, :data, :sender
         
     | 
| 
       92 
80 
     | 
    
         
             
                  def_delegators :@sub_state, :add_refund_account, :add_touched_account, :add_suicide_account
         
     | 
| 
      
 81 
     | 
    
         
            +
                  def_delegators :@state, :find_account, :account_dead?, :store, :fetch, :set_account_code, :get_account_code
         
     | 
| 
       93 
82 
     | 
    
         | 
| 
       94 
     | 
    
         
            -
                  attr_reader :machine_state, :instruction, :sub_state, :block_info, :fork_config
         
     | 
| 
      
 83 
     | 
    
         
            +
                  attr_reader :state, :machine_state, :instruction, :sub_state, :block_info, :fork_config
         
     | 
| 
       95 
84 
     | 
    
         
             
                  attr_accessor :output, :exception
         
     | 
| 
       96 
85 
     | 
    
         | 
| 
       97 
     | 
    
         
            -
                  def initialize(state:, machine_state:, sub_state: nil, instruction:, block_info:, 
     | 
| 
      
 86 
     | 
    
         
            +
                  def initialize(state:, machine_state:, sub_state: nil, instruction:, block_info:,
         
     | 
| 
      
 87 
     | 
    
         
            +
                                 fork_config:, burn_gas_on_exception: true)
         
     | 
| 
       98 
88 
     | 
    
         
             
                    @state = state
         
     | 
| 
       99 
89 
     | 
    
         
             
                    @machine_state = machine_state
         
     | 
| 
       100 
90 
     | 
    
         
             
                    @instruction = instruction
         
     | 
| 
         @@ -102,31 +92,7 @@ module Ciri 
     | 
|
| 
       102 
92 
     | 
    
         
             
                    @output = nil
         
     | 
| 
       103 
93 
     | 
    
         
             
                    @block_info = block_info
         
     | 
| 
       104 
94 
     | 
    
         
             
                    @fork_config = fork_config
         
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                  # store data to address
         
     | 
| 
       108 
     | 
    
         
            -
                  def store(address, key, data)
         
     | 
| 
       109 
     | 
    
         
            -
                    data_is_blank = Ciri::Utils.blank_binary?(data)
         
     | 
| 
       110 
     | 
    
         
            -
                    # key_is_blank = Ciri::Utils.blank_binary?(key)
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
                    return unless data && !data_is_blank
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                    # remove unnecessary null byte from key
         
     | 
| 
       115 
     | 
    
         
            -
                    key = serialize(key).gsub(/\A\0+/, ''.b)
         
     | 
| 
       116 
     | 
    
         
            -
                    key = "\x00".b if key.empty?
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
                    account = find_account address
         
     | 
| 
       119 
     | 
    
         
            -
                    account.storage[key] = serialize(data).rjust(32, "\x00".b)
         
     | 
| 
       120 
     | 
    
         
            -
                    update_account(account)
         
     | 
| 
       121 
     | 
    
         
            -
                  end
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                  # fetch data from address
         
     | 
| 
       124 
     | 
    
         
            -
                  def fetch(address, key)
         
     | 
| 
       125 
     | 
    
         
            -
                    # remove unnecessary null byte from key
         
     | 
| 
       126 
     | 
    
         
            -
                    key = serialize(key).gsub(/\A\0+/, ''.b)
         
     | 
| 
       127 
     | 
    
         
            -
                    key = "\x00".b if key.empty?
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                    find_account(address).storage[key] || ''.b
         
     | 
| 
      
 95 
     | 
    
         
            +
                    @burn_gas_on_exception = burn_gas_on_exception
         
     | 
| 
       130 
96 
     | 
    
         
             
                  end
         
     | 
| 
       131 
97 
     | 
    
         | 
| 
       132 
98 
     | 
    
         
             
                  # run vm
         
     | 
| 
         @@ -138,21 +104,22 @@ module Ciri 
     | 
|
| 
       138 
104 
     | 
    
         
             
                  # low_level create_contract interface
         
     | 
| 
       139 
105 
     | 
    
         
             
                  # CREATE_CONTRACT op is based on this method
         
     | 
| 
       140 
106 
     | 
    
         
             
                  def create_contract(value:, init:)
         
     | 
| 
       141 
     | 
    
         
            -
                     
     | 
| 
      
 107 
     | 
    
         
            +
                    caller_address = instruction.address
         
     | 
| 
      
 108 
     | 
    
         
            +
                    account = find_account(caller_address)
         
     | 
| 
       142 
109 
     | 
    
         | 
| 
       143 
110 
     | 
    
         
             
                    # return contract address 0 represent execution failed
         
     | 
| 
       144 
111 
     | 
    
         
             
                    return 0 unless account.balance >= value || instruction.execute_depth > 1024
         
     | 
| 
       145 
112 
     | 
    
         | 
| 
       146 
     | 
    
         
            -
                     
     | 
| 
      
 113 
     | 
    
         
            +
                    state.increment_nonce(caller_address)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    snapshot = state.snapshot
         
     | 
| 
       147 
115 
     | 
    
         | 
| 
       148 
116 
     | 
    
         
             
                    # generate contract_address
         
     | 
| 
       149 
     | 
    
         
            -
                    material = RLP.encode_simple([ 
     | 
| 
      
 117 
     | 
    
         
            +
                    material = RLP.encode_simple([caller_address.to_s, account.nonce])
         
     | 
| 
       150 
118 
     | 
    
         
             
                    contract_address = Utils.sha3(material)[-20..-1]
         
     | 
| 
       151 
119 
     | 
    
         | 
| 
       152 
120 
     | 
    
         
             
                    # initialize contract account
         
     | 
| 
       153 
121 
     | 
    
         
             
                    contract_account = find_account(contract_address)
         
     | 
| 
       154 
     | 
    
         
            -
                    contract_account.nonce = 1
         
     | 
| 
       155 
     | 
    
         
            -
                    contract_account.code = Utils::BLANK_SHA3
         
     | 
| 
      
 122 
     | 
    
         
            +
                    # contract_account.nonce = 1
         
     | 
| 
       156 
123 
     | 
    
         | 
| 
       157 
124 
     | 
    
         
             
                    # execute initialize code
         
     | 
| 
       158 
125 
     | 
    
         
             
                    create_contract_instruction = instruction.dup
         
     | 
| 
         @@ -160,34 +127,48 @@ module Ciri 
     | 
|
| 
       160 
127 
     | 
    
         
             
                    create_contract_instruction.execute_depth += 1
         
     | 
| 
       161 
128 
     | 
    
         
             
                    create_contract_instruction.address = contract_address
         
     | 
| 
       162 
129 
     | 
    
         | 
| 
      
 130 
     | 
    
         
            +
                    # TODO refactoring: Maybe should use call_message to execute data
         
     | 
| 
       163 
131 
     | 
    
         
             
                    call_instruction(create_contract_instruction) do
         
     | 
| 
       164 
132 
     | 
    
         
             
                      execute
         
     | 
| 
       165 
133 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
                       
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
      
 134 
     | 
    
         
            +
                      deposit_code_gas = fork_config.calculate_deposit_code_gas(output)
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                      if deposit_code_gas > remain_gas
         
     | 
| 
      
 137 
     | 
    
         
            +
                        # deposit_code_gas not enough
         
     | 
| 
      
 138 
     | 
    
         
            +
                        contract_address = 0
         
     | 
| 
      
 139 
     | 
    
         
            +
                      elsif exception
         
     | 
| 
      
 140 
     | 
    
         
            +
                        state.touch_account(contract_address)
         
     | 
| 
       168 
141 
     | 
    
         
             
                        contract_address = 0
         
     | 
| 
      
 142 
     | 
    
         
            +
                        state.revert(snapshot)
         
     | 
| 
       169 
143 
     | 
    
         
             
                      else
         
     | 
| 
       170 
144 
     | 
    
         
             
                        # set contract code
         
     | 
| 
       171 
     | 
    
         
            -
                         
     | 
| 
      
 145 
     | 
    
         
            +
                        set_account_code(contract_address, output)
         
     | 
| 
      
 146 
     | 
    
         
            +
                        # minus deposit_code_fee
         
     | 
| 
      
 147 
     | 
    
         
            +
                        machine_state.consume_gas deposit_code_gas
         
     | 
| 
       172 
148 
     | 
    
         
             
                        # transact value
         
     | 
| 
       173 
149 
     | 
    
         
             
                        account.balance -= value
         
     | 
| 
       174 
150 
     | 
    
         
             
                        contract_account.balance += value
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                        state.set_balance(contract_address, contract_account.balance)
         
     | 
| 
      
 153 
     | 
    
         
            +
                        state.set_balance(caller_address, account.balance)
         
     | 
| 
      
 154 
     | 
    
         
            +
                        state.commit(snapshot)
         
     | 
| 
       175 
155 
     | 
    
         
             
                      end
         
     | 
| 
      
 156 
     | 
    
         
            +
                      [contract_address, exception]
         
     | 
| 
       176 
157 
     | 
    
         
             
                    end
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                    # update account
         
     | 
| 
       179 
     | 
    
         
            -
                    update_account(contract_account)
         
     | 
| 
       180 
     | 
    
         
            -
                    update_account(account)
         
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
                    contract_address
         
     | 
| 
       183 
158 
     | 
    
         
             
                  end
         
     | 
| 
       184 
159 
     | 
    
         | 
| 
       185 
160 
     | 
    
         
             
                  # low level call message interface
         
     | 
| 
       186 
161 
     | 
    
         
             
                  # CALL, CALLCODE, DELEGATECALL ops is base on this method
         
     | 
| 
       187 
     | 
    
         
            -
                  def call_message(sender:, value:, receipt:, data:, code_address:)
         
     | 
| 
      
 162 
     | 
    
         
            +
                  def call_message(sender:, value:, receipt:, data:, code_address: receipt)
         
     | 
| 
       188 
163 
     | 
    
         
             
                    # return status code 0 represent execution failed
         
     | 
| 
       189 
164 
     | 
    
         
             
                    return [0, ''.b] unless value <= find_account(sender).balance && instruction.execute_depth <= 1024
         
     | 
| 
       190 
165 
     | 
    
         | 
| 
      
 166 
     | 
    
         
            +
                    state.increment_nonce(sender)
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                    snapshot = state.snapshot
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    transact(sender: sender, value: value, to: receipt)
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
       191 
172 
     | 
    
         
             
                    message_call_instruction = instruction.dup
         
     | 
| 
       192 
173 
     | 
    
         
             
                    message_call_instruction.address = receipt
         
     | 
| 
       193 
174 
     | 
    
         
             
                    message_call_instruction.sender = sender
         
     | 
| 
         @@ -196,54 +177,48 @@ module Ciri 
     | 
|
| 
       196 
177 
     | 
    
         
             
                    message_call_instruction.execute_depth += 1
         
     | 
| 
       197 
178 
     | 
    
         | 
| 
       198 
179 
     | 
    
         
             
                    message_call_instruction.data = data
         
     | 
| 
       199 
     | 
    
         
            -
                    message_call_instruction.bytes_code =  
     | 
| 
      
 180 
     | 
    
         
            +
                    message_call_instruction.bytes_code = get_account_code(code_address)
         
     | 
| 
       200 
181 
     | 
    
         | 
| 
       201 
     | 
    
         
            -
                    transact(sender: sender, value: value, to: receipt)
         
     | 
| 
       202 
182 
     | 
    
         
             
                    call_instruction(message_call_instruction) do
         
     | 
| 
       203 
183 
     | 
    
         
             
                      execute
         
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
       205 
     | 
    
         
            -
                       
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                      if exception
         
     | 
| 
      
 186 
     | 
    
         
            +
                        state.revert(snapshot)
         
     | 
| 
      
 187 
     | 
    
         
            +
                      else
         
     | 
| 
      
 188 
     | 
    
         
            +
                        state.commit(snapshot)
         
     | 
| 
      
 189 
     | 
    
         
            +
                      end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                      [status, output || ''.b, exception]
         
     | 
| 
       206 
192 
     | 
    
         
             
                    end
         
     | 
| 
       207 
193 
     | 
    
         
             
                  end
         
     | 
| 
       208 
194 
     | 
    
         | 
| 
      
 195 
     | 
    
         
            +
                  def status
         
     | 
| 
      
 196 
     | 
    
         
            +
                    exception.nil? ? 0 : 1
         
     | 
| 
      
 197 
     | 
    
         
            +
                  end
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
       209 
199 
     | 
    
         
             
                  # jump to pc
         
     | 
| 
       210 
200 
     | 
    
         
             
                  # only valid if current op code is allowed to modify pc
         
     | 
| 
       211 
201 
     | 
    
         
             
                  def jump_to(pc)
         
     | 
| 
       212 
202 
     | 
    
         
             
                    @jump_to = pc
         
     | 
| 
       213 
203 
     | 
    
         
             
                  end
         
     | 
| 
       214 
204 
     | 
    
         | 
| 
       215 
     | 
    
         
            -
                  def account_dead?(address)
         
     | 
| 
       216 
     | 
    
         
            -
                    Account.account_dead?(@state, address)
         
     | 
| 
       217 
     | 
    
         
            -
                  end
         
     | 
| 
       218 
     | 
    
         
            -
             
     | 
| 
       219 
     | 
    
         
            -
                  def find_account(address)
         
     | 
| 
       220 
     | 
    
         
            -
                    Account.find_account(@state, address)
         
     | 
| 
       221 
     | 
    
         
            -
                  end
         
     | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
       223 
     | 
    
         
            -
                  # the only method which touch state
         
     | 
| 
       224 
     | 
    
         
            -
                  # VM do not consider state revert/commit, we let it to state implementation
         
     | 
| 
       225 
     | 
    
         
            -
                  def update_account(account)
         
     | 
| 
       226 
     | 
    
         
            -
                    address = account.address.to_s
         
     | 
| 
       227 
     | 
    
         
            -
                    @state[address] = account
         
     | 
| 
       228 
     | 
    
         
            -
                    add_touched_account(account)
         
     | 
| 
       229 
     | 
    
         
            -
                  end
         
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
       231 
205 
     | 
    
         
             
                  def add_log_entry(topics, log_data)
         
     | 
| 
       232 
     | 
    
         
            -
                    sub_state.log_series <<  
     | 
| 
      
 206 
     | 
    
         
            +
                    sub_state.log_series << LogEntry.new(address: instruction.address, topics: topics, data: log_data)
         
     | 
| 
       233 
207 
     | 
    
         
             
                  end
         
     | 
| 
       234 
208 
     | 
    
         | 
| 
       235 
209 
     | 
    
         
             
                  # transact value from sender to target address
         
     | 
| 
       236 
210 
     | 
    
         
             
                  def transact(sender:, value:, to:)
         
     | 
| 
       237 
     | 
    
         
            -
                     
     | 
| 
       238 
     | 
    
         
            -
                     
     | 
| 
      
 211 
     | 
    
         
            +
                    sender_account = find_account(sender)
         
     | 
| 
      
 212 
     | 
    
         
            +
                    to_account = find_account(to)
         
     | 
| 
       239 
213 
     | 
    
         | 
| 
       240 
     | 
    
         
            -
                    raise VMError.new("balance not enough") if  
     | 
| 
      
 214 
     | 
    
         
            +
                    raise VMError.new("balance not enough") if sender_account.balance < value
         
     | 
| 
       241 
215 
     | 
    
         | 
| 
       242 
     | 
    
         
            -
                     
     | 
| 
       243 
     | 
    
         
            -
                     
     | 
| 
      
 216 
     | 
    
         
            +
                    sender_account.balance -= value
         
     | 
| 
      
 217 
     | 
    
         
            +
                    to_account.balance += value
         
     | 
| 
       244 
218 
     | 
    
         | 
| 
       245 
     | 
    
         
            -
                     
     | 
| 
       246 
     | 
    
         
            -
                     
     | 
| 
      
 219 
     | 
    
         
            +
                    state.set_nonce(sender, sender_account.nonce)
         
     | 
| 
      
 220 
     | 
    
         
            +
                    state.set_balance(sender, sender_account.balance)
         
     | 
| 
      
 221 
     | 
    
         
            +
                    state.set_balance(to, to_account.balance)
         
     | 
| 
       247 
222 
     | 
    
         
             
                  end
         
     | 
| 
       248 
223 
     | 
    
         | 
| 
       249 
224 
     | 
    
         
             
                  # call instruction
         
     | 
| 
         @@ -268,13 +243,14 @@ module Ciri 
     | 
|
| 
       268 
243 
     | 
    
         
             
                  def execute
         
     | 
| 
       269 
244 
     | 
    
         
             
                    loop do
         
     | 
| 
       270 
245 
     | 
    
         
             
                      if (@exception ||= check_exception(@state, machine_state, instruction))
         
     | 
| 
       271 
     | 
    
         
            -
                         
     | 
| 
      
 246 
     | 
    
         
            +
                        if @burn_gas_on_exception
         
     | 
| 
      
 247 
     | 
    
         
            +
                          debug("exception: #{@exception}, burn gas #{machine_state.remain_gas} to zero")
         
     | 
| 
      
 248 
     | 
    
         
            +
                          machine_state.consume_gas machine_state.remain_gas
         
     | 
| 
      
 249 
     | 
    
         
            +
                        end
         
     | 
| 
       272 
250 
     | 
    
         
             
                        return [EMPTY_SET, machine_state, SubState::EMPTY, instruction, EMPTY_SET]
         
     | 
| 
       273 
251 
     | 
    
         
             
                      elsif get_op(machine_state.pc) == OP::REVERT
         
     | 
| 
       274 
252 
     | 
    
         
             
                        o = halt
         
     | 
| 
       275 
     | 
    
         
            -
                         
     | 
| 
       276 
     | 
    
         
            -
                        machine_state.gas_remain -= gas_cost
         
     | 
| 
       277 
     | 
    
         
            -
                        return [EMPTY_SET, machine_state, sub_state, instruction, o]
         
     | 
| 
      
 253 
     | 
    
         
            +
                        return [EMPTY_SET, machine_state, SubState::EMPTY, instruction, o]
         
     | 
| 
       278 
254 
     | 
    
         
             
                      elsif (o = halt) != EMPTY_SET
         
     | 
| 
       279 
255 
     | 
    
         
             
                        return [@state, machine_state, sub_state, instruction, o]
         
     | 
| 
       280 
256 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -294,23 +270,23 @@ module Ciri 
     | 
|
| 
       294 
270 
     | 
    
         | 
| 
       295 
271 
     | 
    
         
             
                    raise "can't find operation #{w}, pc #{ms.pc}" unless operation
         
     | 
| 
       296 
272 
     | 
    
         | 
| 
       297 
     | 
    
         
            -
                    op_cost = fork_config. 
     | 
| 
       298 
     | 
    
         
            -
                    old_memory_cost = fork_config. 
     | 
| 
       299 
     | 
    
         
            -
                    ms. 
     | 
| 
      
 273 
     | 
    
         
            +
                    op_cost = fork_config.gas_of_operation(self)
         
     | 
| 
      
 274 
     | 
    
         
            +
                    old_memory_cost = fork_config.gas_of_memory(ms.memory_item)
         
     | 
| 
      
 275 
     | 
    
         
            +
                    ms.consume_gas op_cost
         
     | 
| 
       300 
276 
     | 
    
         | 
| 
       301 
277 
     | 
    
         
             
                    prev_sub_state = sub_state.dup
         
     | 
| 
       302 
278 
     | 
    
         | 
| 
       303 
279 
     | 
    
         
             
                    # call operation
         
     | 
| 
       304 
280 
     | 
    
         
             
                    operation.call(self)
         
     | 
| 
       305 
281 
     | 
    
         
             
                    # calculate gas_cost
         
     | 
| 
       306 
     | 
    
         
            -
                    new_memory_cost = fork_config. 
     | 
| 
      
 282 
     | 
    
         
            +
                    new_memory_cost = fork_config.gas_of_memory(ms.memory_item)
         
     | 
| 
       307 
283 
     | 
    
         
             
                    memory_gas_cost = new_memory_cost - old_memory_cost
         
     | 
| 
       308 
284 
     | 
    
         | 
| 
       309 
     | 
    
         
            -
                    if ms. 
     | 
| 
       310 
     | 
    
         
            -
                      ms. 
     | 
| 
      
 285 
     | 
    
         
            +
                    if ms.remain_gas >= memory_gas_cost
         
     | 
| 
      
 286 
     | 
    
         
            +
                      ms.consume_gas memory_gas_cost
         
     | 
| 
       311 
287 
     | 
    
         
             
                    else
         
     | 
| 
       312 
288 
     | 
    
         
             
                      # memory gas_not_enough
         
     | 
| 
       313 
     | 
    
         
            -
                      @exception = GasNotEnoughError.new "gas not enough: gas remain:#{ms. 
     | 
| 
      
 289 
     | 
    
         
            +
                      @exception = GasNotEnoughError.new "gas not enough: gas remain:#{ms.remain_gas} gas cost: #{memory_gas_cost}"
         
     | 
| 
       314 
290 
     | 
    
         
             
                    end
         
     | 
| 
       315 
291 
     | 
    
         | 
| 
       316 
292 
     | 
    
         
             
                    # revert sub_state and return if exception occur
         
     | 
| 
         @@ -356,8 +332,8 @@ module Ciri 
     | 
|
| 
       356 
332 
     | 
    
         
             
                      InvalidOpCodeError.new "can't find op code #{w}"
         
     | 
| 
       357 
333 
     | 
    
         
             
                    when ms.stack.size < (consume = OP.input_count(w))
         
     | 
| 
       358 
334 
     | 
    
         
             
                      StackError.new "stack not enough: stack:#{ms.stack.size} next consume: #{consume}"
         
     | 
| 
       359 
     | 
    
         
            -
                    when ms. 
     | 
| 
       360 
     | 
    
         
            -
                      GasNotEnoughError.new "gas not enough: gas remain:#{ms. 
     | 
| 
      
 335 
     | 
    
         
            +
                    when ms.remain_gas < (gas_cost = fork_config.gas_of_operation(self))
         
     | 
| 
      
 336 
     | 
    
         
            +
                      GasNotEnoughError.new "gas not enough: gas remain:#{ms.remain_gas} gas cost: #{gas_cost}"
         
     | 
| 
       361 
337 
     | 
    
         
             
                    when w == OP::JUMP && instruction.destinations.include?(ms.get_stack(0, Integer))
         
     | 
| 
       362 
338 
     | 
    
         
             
                      InvalidJumpError.new "invalid jump dest #{ms.get_stack(0, Integer)}"
         
     | 
| 
       363 
339 
     | 
    
         
             
                    when w == OP::JUMPI && ms.get_stack(1, Integer) != 0 && instruction.destinations.include?(ms.get_stack(0, Integer))
         
     |