reth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +6 -0
- data/bin/reth +208 -0
- data/lib/reth.rb +44 -0
- data/lib/reth/account.rb +195 -0
- data/lib/reth/account_service.rb +361 -0
- data/lib/reth/app.rb +15 -0
- data/lib/reth/chain_service.rb +500 -0
- data/lib/reth/config.rb +88 -0
- data/lib/reth/db_service.rb +90 -0
- data/lib/reth/duplicates_filter.rb +29 -0
- data/lib/reth/eth_protocol.rb +209 -0
- data/lib/reth/genesisdata/genesis_frontier.json +26691 -0
- data/lib/reth/genesisdata/genesis_morden.json +27 -0
- data/lib/reth/genesisdata/genesis_olympic.json +48 -0
- data/lib/reth/jsonrpc.rb +13 -0
- data/lib/reth/jsonrpc/app.rb +79 -0
- data/lib/reth/jsonrpc/filter.rb +288 -0
- data/lib/reth/jsonrpc/handler.rb +424 -0
- data/lib/reth/jsonrpc/helper.rb +156 -0
- data/lib/reth/jsonrpc/server.rb +24 -0
- data/lib/reth/jsonrpc/service.rb +37 -0
- data/lib/reth/keystore.rb +150 -0
- data/lib/reth/leveldb_service.rb +79 -0
- data/lib/reth/profile.rb +66 -0
- data/lib/reth/sync_task.rb +273 -0
- data/lib/reth/synchronizer.rb +192 -0
- data/lib/reth/transient_block.rb +40 -0
- data/lib/reth/utils.rb +22 -0
- data/lib/reth/version.rb +3 -0
- metadata +201 -0
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "nonce": "0x00006d6f7264656e",
         | 
| 3 | 
            +
              "difficulty": "0x20000",
         | 
| 4 | 
            +
              "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
         | 
| 5 | 
            +
              "coinbase": "0x0000000000000000000000000000000000000000",
         | 
| 6 | 
            +
              "timestamp": "0x00",
         | 
| 7 | 
            +
              "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
         | 
| 8 | 
            +
              "extraData": "0x",
         | 
| 9 | 
            +
              "gasLimit": "0x2FEFD8",
         | 
| 10 | 
            +
              "alloc": {
         | 
| 11 | 
            +
                "0000000000000000000000000000000000000001": {
         | 
| 12 | 
            +
                  "balance": "1"
         | 
| 13 | 
            +
                },
         | 
| 14 | 
            +
                "0000000000000000000000000000000000000002": {
         | 
| 15 | 
            +
                  "balance": "1"
         | 
| 16 | 
            +
                },
         | 
| 17 | 
            +
                "0000000000000000000000000000000000000003": {
         | 
| 18 | 
            +
                  "balance": "1"
         | 
| 19 | 
            +
                },
         | 
| 20 | 
            +
                "0000000000000000000000000000000000000004": {
         | 
| 21 | 
            +
                  "balance": "1"
         | 
| 22 | 
            +
                },
         | 
| 23 | 
            +
                "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": {
         | 
| 24 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 25 | 
            +
                }
         | 
| 26 | 
            +
              }
         | 
| 27 | 
            +
            }
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "nonce": "0x0000000000000042",
         | 
| 3 | 
            +
              "difficulty": "0x20000",
         | 
| 4 | 
            +
              "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
         | 
| 5 | 
            +
              "coinbase": "0x0000000000000000000000000000000000000000",
         | 
| 6 | 
            +
              "timestamp": "0x00",
         | 
| 7 | 
            +
              "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
         | 
| 8 | 
            +
              "extraData": "",
         | 
| 9 | 
            +
              "gasLimit": "0x2fefd8",
         | 
| 10 | 
            +
              "alloc": {
         | 
| 11 | 
            +
                "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {
         | 
| 12 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 13 | 
            +
                },
         | 
| 14 | 
            +
                "e6716f9544a56c530d868e4bfbacb172315bdead": {
         | 
| 15 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 16 | 
            +
                },
         | 
| 17 | 
            +
                "b9c015918bdaba24b4ff057a92a3873d6eb201be": {
         | 
| 18 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 19 | 
            +
                },
         | 
| 20 | 
            +
                "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {
         | 
| 21 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 22 | 
            +
                },
         | 
| 23 | 
            +
                "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {
         | 
| 24 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 25 | 
            +
                },
         | 
| 26 | 
            +
                "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {
         | 
| 27 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 28 | 
            +
                },
         | 
| 29 | 
            +
                "6c386a4b26f73c802f34673f7248bb118f97424a": {
         | 
| 30 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 31 | 
            +
                },
         | 
| 32 | 
            +
                "e4157b34ea9615cfbde6b4fda419828124b70c78": {
         | 
| 33 | 
            +
                  "balance": "1606938044258990275541962092341162602522202993782792835301376"
         | 
| 34 | 
            +
                },
         | 
| 35 | 
            +
                "0000000000000000000000000000000000000001": {
         | 
| 36 | 
            +
                  "balance": "1"
         | 
| 37 | 
            +
                },
         | 
| 38 | 
            +
                "0000000000000000000000000000000000000002": {
         | 
| 39 | 
            +
                  "balance": "1"
         | 
| 40 | 
            +
                },
         | 
| 41 | 
            +
                "0000000000000000000000000000000000000003": {
         | 
| 42 | 
            +
                  "balance": "1"
         | 
| 43 | 
            +
                },
         | 
| 44 | 
            +
                "0000000000000000000000000000000000000004": {
         | 
| 45 | 
            +
                  "balance": "1"
         | 
| 46 | 
            +
                }
         | 
| 47 | 
            +
              }
         | 
| 48 | 
            +
            }
         | 
    
        data/lib/reth/jsonrpc.rb
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
            require 'rack'
         | 
| 3 | 
            +
            require 'sinatra/base'
         | 
| 4 | 
            +
            require 'sinatra/json'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'ethereum'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'reth/jsonrpc/helper'
         | 
| 9 | 
            +
            require 'reth/jsonrpc/filter'
         | 
| 10 | 
            +
            require 'reth/jsonrpc/handler'
         | 
| 11 | 
            +
            require 'reth/jsonrpc/server'
         | 
| 12 | 
            +
            require 'reth/jsonrpc/service'
         | 
| 13 | 
            +
            require 'reth/jsonrpc/app'
         | 
| @@ -0,0 +1,79 @@ | |
| 1 | 
            +
            module Reth
         | 
| 2 | 
            +
            module JSONRPC
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class App < Sinatra::Base
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                configure do
         | 
| 7 | 
            +
                  enable :logging
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                CORS_ORIGIN = "http://localhost:8080"
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                options "*" do
         | 
| 13 | 
            +
                  response.headers["Allow"] = "POST,OPTIONS"
         | 
| 14 | 
            +
                  response.headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept"
         | 
| 15 | 
            +
                  response.headers["Access-Control-Allow-Origin"] = "http://localhost:8080"
         | 
| 16 | 
            +
                  response.headers["Access-Control-Allow-Methods"] = "POST"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  200
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                post '/' do
         | 
| 22 | 
            +
                  response.headers["Access-Control-Allow-Origin"] = CORS_ORIGIN
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  begin
         | 
| 25 | 
            +
                    data = JSON.parse request.body.read
         | 
| 26 | 
            +
                    puts "Params: #{data.inspect}"
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    result = if data.instance_of?(Array)
         | 
| 29 | 
            +
                               data.map {|d| dispatch d }
         | 
| 30 | 
            +
                             else
         | 
| 31 | 
            +
                               dispatch data
         | 
| 32 | 
            +
                             end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    json result
         | 
| 35 | 
            +
                  rescue JSON::ParserError
         | 
| 36 | 
            +
                    puts $!
         | 
| 37 | 
            +
                    puts $!.backtrace[0,10].join("\n")
         | 
| 38 | 
            +
                    json jsonrpc: '2.0', error: $!
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def initialize(node)
         | 
| 43 | 
            +
                  @node = node
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  @default_block = 'latest'
         | 
| 46 | 
            +
                  @default_address = Account.test_accounts.keys.first
         | 
| 47 | 
            +
                  @default_startgas = 500 * 1000
         | 
| 48 | 
            +
                  @default_gas_price = 60.shannon
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  super()
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                private
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                include Handler
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def dispatch(data)
         | 
| 58 | 
            +
                  # TODO: filter injection, validate method names
         | 
| 59 | 
            +
                  result = send :"handle_#{data['method']}", *data['params']
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  {jsonrpc: data['jsonrpc'], id: data['id'], result: result}
         | 
| 62 | 
            +
                rescue NoMethodError
         | 
| 63 | 
            +
                  if $!.message =~ /handle_([a-zA-Z_]+)/
         | 
| 64 | 
            +
                    {jsonrpc: '2.0', id: data['id'], error: "jsonrpc method not defined: #{$1}"}
         | 
| 65 | 
            +
                  else
         | 
| 66 | 
            +
                    puts $!
         | 
| 67 | 
            +
                    puts $!.backtrace[0,10].join("\n")
         | 
| 68 | 
            +
                    {jsonrpc: data['jsonrpc'], id: data['id'], error: $!}
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                rescue
         | 
| 71 | 
            +
                  puts $!
         | 
| 72 | 
            +
                  puts $!.backtrace[0,10].join("\n")
         | 
| 73 | 
            +
                  {jsonrpc: data['jsonrpc'], id: data['id'], error: $!}
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            end
         | 
| 79 | 
            +
            end
         | 
| @@ -0,0 +1,288 @@ | |
| 1 | 
            +
            module Reth
         | 
| 2 | 
            +
            module JSONRPC
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class Filter
         | 
| 5 | 
            +
                class <<self
         | 
| 6 | 
            +
                  def next_id
         | 
| 7 | 
            +
                    @next_id ||= 0
         | 
| 8 | 
            +
                    @next_id += 1
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def map
         | 
| 12 | 
            +
                    @map ||= {}
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def find(id)
         | 
| 16 | 
            +
                    map[id]
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def delete(id)
         | 
| 20 | 
            +
                    map.delete id
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def include?(id)
         | 
| 24 | 
            +
                    map.include?(id)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              class LogFilter
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                class <<self
         | 
| 32 | 
            +
                  def create(obj, chain)
         | 
| 33 | 
            +
                    f = new obj, chain
         | 
| 34 | 
            +
                    id = Filter.next_id
         | 
| 35 | 
            +
                    Filter.map[id] = f
         | 
| 36 | 
            +
                    id
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                include Helper
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def initialize(obj, chain)
         | 
| 43 | 
            +
                  @chain = chain
         | 
| 44 | 
            +
                  @first_block, @last_block, @addresses, @topics = parse_obj obj
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  @last_head = @chain.head
         | 
| 47 | 
            +
                  @last_block_checked = nil
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  @log_dict = {}
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def check
         | 
| 53 | 
            +
                  first, last = get_from_to @first_block, @last_block
         | 
| 54 | 
            +
                  first = [@last_head.number + 1, first].min if @first_block.is_a?(String)
         | 
| 55 | 
            +
                  raise "first must not be greater than last" unless first <= last
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  if @last_block_checked
         | 
| 58 | 
            +
                    first = [@last_block_checked.number + 1, first].max
         | 
| 59 | 
            +
                    return {} if first > last
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  blocks_to_check = []
         | 
| 63 | 
            +
                  (first...last).each do |n|
         | 
| 64 | 
            +
                    blocks_to_check.push @chain.index.get_block_by_number(n)
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  head = @chain.head
         | 
| 68 | 
            +
                  head_candidate = @chain.head_candidate
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  if last == head_candidate.number
         | 
| 71 | 
            +
                    blocks_to_check.push head_candidate
         | 
| 72 | 
            +
                  else
         | 
| 73 | 
            +
                    blocks_to_check.push @chain.get(@chain.index.get_block_by_number(last))
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  int32 = RLP::Sedes::BigEndianInt.new 32
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  new_logs = {}
         | 
| 79 | 
            +
                  blocks_to_check.each_with_index do |block, i|
         | 
| 80 | 
            +
                    unless [Ethereum::Block, Ethereum::CachedBlock].include?(block.class)
         | 
| 81 | 
            +
                      # must be blockhash
         | 
| 82 | 
            +
                      bloom = @chain.get_bloom block
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                      if @addresses
         | 
| 85 | 
            +
                        pass_address_check = @addresses.any? {|addr| Ethereum::Bloom.query(bloom, addr) }
         | 
| 86 | 
            +
                        next unless pass_address_check
         | 
| 87 | 
            +
                      end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                      topics = (@topics || []).map {|t| int32.serialize(t) }
         | 
| 90 | 
            +
                      topic_bloom = Ethereum::Bloom.from_array topics
         | 
| 91 | 
            +
                      next if Ethereum::Bloom.combine(bloom, topic_bloom) != bloom
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                      block = @chain.get block
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                    r_idx = nil
         | 
| 97 | 
            +
                    l_idx = nil
         | 
| 98 | 
            +
                    log = nil
         | 
| 99 | 
            +
                    block.get_receipts.each_with_index do |receipt, ri|
         | 
| 100 | 
            +
                      r_idx = ri
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                      receipt.logs.each_with_index do |_log, li|
         | 
| 103 | 
            +
                        log = _log
         | 
| 104 | 
            +
                        l_idx = li
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                        next if @addresses && !@addresses.include?(log.address)
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                        if @topics
         | 
| 109 | 
            +
                          topic_match = log.topics.size >= @topics.size
         | 
| 110 | 
            +
                          next unless topic_match
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                          @topics.zip(log.topics).each do |filter_topic, log_topic|
         | 
| 113 | 
            +
                            if filter_topic && filter_topic != log_topic
         | 
| 114 | 
            +
                              topic_match = false
         | 
| 115 | 
            +
                              break
         | 
| 116 | 
            +
                            end
         | 
| 117 | 
            +
                          end
         | 
| 118 | 
            +
                          next unless topic_match
         | 
| 119 | 
            +
                        end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                        tx = block.get_transaction r_idx
         | 
| 122 | 
            +
                        id = Ethereum::Utils.keccak256 "#{tx.full_hash}#{l_idx}"
         | 
| 123 | 
            +
                        pending = block == head_candidate
         | 
| 124 | 
            +
                        new_logs[id] = {
         | 
| 125 | 
            +
                          log: log,
         | 
| 126 | 
            +
                          log_idx: l_idx,
         | 
| 127 | 
            +
                          block: block,
         | 
| 128 | 
            +
                          txhash: tx.full_hash,
         | 
| 129 | 
            +
                          tx_idx: r_idx
         | 
| 130 | 
            +
                        }
         | 
| 131 | 
            +
                      end
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  @last_block_checked = if blocks_to_check.last != head_candidate
         | 
| 136 | 
            +
                                          blocks_to_check.last
         | 
| 137 | 
            +
                                        else
         | 
| 138 | 
            +
                                          blocks_to_check.size >= 2 ? blocks_to_check[-2] : nil
         | 
| 139 | 
            +
                                        end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  if @last_block_checked && ![Ethereum::Block, Ethereum::CachedBlock].include?(@last_block_checked.class)
         | 
| 142 | 
            +
                    @last_block_checked = @chain.get @last_block_checked
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                  actually_new_ids = new_logs.keys - @log_dict.keys
         | 
| 146 | 
            +
                  @log_dict.merge! new_logs
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  actually_new_ids.map {|id| [id, new_logs[id]] }.to_h
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                def logs
         | 
| 152 | 
            +
                  check
         | 
| 153 | 
            +
                  @log_dict.values
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                def new_logs
         | 
| 157 | 
            +
                  check.values
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                def to_s
         | 
| 161 | 
            +
                  "<Filter(addressed=#{@addresses}, topics=#{@topics}, first=#{@first_block}, last=#{@last_block})>"
         | 
| 162 | 
            +
                end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                private
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                def parse_obj(obj)
         | 
| 167 | 
            +
                  raise ArgumentError, 'obj must be a Hash' unless obj.instance_of?(Hash)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  addresses = case obj['address']
         | 
| 170 | 
            +
                              when String
         | 
| 171 | 
            +
                                [hex_to_bytes(obj['address'])]
         | 
| 172 | 
            +
                              when Array
         | 
| 173 | 
            +
                                obj['address'].map {|addr| hex_to_bytes(addr) }
         | 
| 174 | 
            +
                              when NilClass
         | 
| 175 | 
            +
                                nil
         | 
| 176 | 
            +
                              else
         | 
| 177 | 
            +
                                raise ArgumentError, "address must be String or Array of Strings"
         | 
| 178 | 
            +
                              end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                  topics = nil
         | 
| 181 | 
            +
                  if obj.has_key?('topics')
         | 
| 182 | 
            +
                    topics = []
         | 
| 183 | 
            +
                    obj['topics'].each do |t|
         | 
| 184 | 
            +
                      if t
         | 
| 185 | 
            +
                        topics.push(Ethereum::Utils.big_endian_to_int hex_to_bytes(t))
         | 
| 186 | 
            +
                      else
         | 
| 187 | 
            +
                        topics.push(nil)
         | 
| 188 | 
            +
                      end
         | 
| 189 | 
            +
                    end
         | 
| 190 | 
            +
                  end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                  from_block = decode_block_tag(obj['fromBlock'] || 'latest')
         | 
| 193 | 
            +
                  to_block = decode_block_tag(obj['toBlock'] || 'latest')
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                  from, to = get_from_to from_block, to_block
         | 
| 196 | 
            +
                  raise ArgumentError, 'fromBlock must not be newer than toBlock' if from > to
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                  return from_block, to_block, addresses, topics
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                def get_from_to(from_block, to_block)
         | 
| 202 | 
            +
                  block_tags = {
         | 
| 203 | 
            +
                    'earliest' => 0,
         | 
| 204 | 
            +
                    'latest' => @chain.head.number,
         | 
| 205 | 
            +
                    'pending' => @chain.head_candidate.number
         | 
| 206 | 
            +
                  }
         | 
| 207 | 
            +
                  from = from_block.is_a?(Integer) ? from_block : block_tags[from_block]
         | 
| 208 | 
            +
                  to = to_block.is_a?(Integer) ? to_block : block_tags[to_block]
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                  return from, to
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
              end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
              class BlockFilter
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                class <<self
         | 
| 218 | 
            +
                  def create(chain)
         | 
| 219 | 
            +
                    f = new chain
         | 
| 220 | 
            +
                    id = Filter.next_id
         | 
| 221 | 
            +
                    Filter.map[id] = f
         | 
| 222 | 
            +
                    id
         | 
| 223 | 
            +
                  end
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                def initialize(chain)
         | 
| 227 | 
            +
                  @chain = chain
         | 
| 228 | 
            +
                  @latest_block = chain.head
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                def check
         | 
| 232 | 
            +
                  new_blocks = []
         | 
| 233 | 
            +
                  block = @chain.head
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                  while block.number > @latest_block.number
         | 
| 236 | 
            +
                    new_blocks.push block
         | 
| 237 | 
            +
                    block = block.get_parent
         | 
| 238 | 
            +
                  end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                  puts "previous latest block not in current chain!" if block != @latest_block
         | 
| 241 | 
            +
                  @latest_block = new_blocks.first if new_blocks.size > 0
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                  new_blocks.reverse
         | 
| 244 | 
            +
                end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
              end
         | 
| 247 | 
            +
             | 
| 248 | 
            +
              class PendingTransactionFilter
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                class <<self
         | 
| 251 | 
            +
                  def create(chain)
         | 
| 252 | 
            +
                    f = new chain
         | 
| 253 | 
            +
                    id = Filter.next_id
         | 
| 254 | 
            +
                    Filter.map[id] = f
         | 
| 255 | 
            +
                    id
         | 
| 256 | 
            +
                  end
         | 
| 257 | 
            +
                end
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                def initialize(chain)
         | 
| 260 | 
            +
                  @chain = chain
         | 
| 261 | 
            +
                  @latest_block = @chain.head_candidate
         | 
| 262 | 
            +
                  @reported_txs = []
         | 
| 263 | 
            +
                end
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                def check
         | 
| 266 | 
            +
                  head_candidate = @chain.head_candidate
         | 
| 267 | 
            +
                  pending_txs = head_candidate.get_transactions
         | 
| 268 | 
            +
                  new_txs = pending_txs.select {|tx| !@reported_txs.include?(tx.full_hash) }
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                  block = head_candidate.get_parent
         | 
| 271 | 
            +
                  while block.number >= @latest_block.number
         | 
| 272 | 
            +
                    block.get_transactions.reverse.each do |tx|
         | 
| 273 | 
            +
                      new_txs.push(tx) unless @reported_txs.include?(tx.full_hash)
         | 
| 274 | 
            +
                    end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                    block = block.get_parent
         | 
| 277 | 
            +
                  end
         | 
| 278 | 
            +
             | 
| 279 | 
            +
                  @latest_block = head_candidate
         | 
| 280 | 
            +
                  @reported_txs = pending_txs.map(&:full_hash)
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                  new_txs.reverse
         | 
| 283 | 
            +
                end
         | 
| 284 | 
            +
             | 
| 285 | 
            +
              end
         | 
| 286 | 
            +
             | 
| 287 | 
            +
            end
         | 
| 288 | 
            +
            end
         |