class Lapidar::Runner

Attributes

buschtelefon_endpoint[R]
chain[R]
logger[R]
punch_queue[R]

Public Class Methods

new(buschtelefon_endpoint) click to toggle source
# File lib/lapidar/runner.rb, line 7
def initialize(buschtelefon_endpoint)
  @logger = Logger.new(StringIO.new)
  @buschtelefon_endpoint = buschtelefon_endpoint
  @chain = Persistence.load_chain("#{@buschtelefon_endpoint.port}.json") || Chain.new
  @incoming_blocks = Queue.new
  @punch_queue = SizedQueue.new(1)
  @should_stop = nil
  @threads = []

  # Reload currently strongest chain into buschtelefon_endpoint
  if @chain.blocks.any?
    @buschtelefon_endpoint.load_messages(@chain.blocks.map(&:to_h).map(&:to_json))
  end
end

Public Instance Methods

start() click to toggle source
# File lib/lapidar/runner.rb, line 22
def start
  @should_stop = false
  @threads = [consumer, local_producer, network_producer]
  @threads.each { |t| t.abort_on_exception = true }
  @threads.each(&:join)
end
stop() click to toggle source
# File lib/lapidar/runner.rb, line 29
def stop
  @should_stop = true
  Thread.pass
  Persistence.save_chain("#{@buschtelefon_endpoint.port}.json", @chain)
  @threads.each(&:exit)
end

Private Instance Methods

consumer() click to toggle source
# File lib/lapidar/runner.rb, line 38
def consumer
  Thread.new do
    until @should_stop
      begin
        @chain.add(@incoming_blocks.pop)
        @logger.info("consumer") { "+" }
      rescue => e
        @logger.debug("consumer") { "Block cannot be added to chain: #{e.message}" }
        @logger.info("consumer") { "_" }
      end
    end
  end
end
local_producer() click to toggle source
# File lib/lapidar/runner.rb, line 52
def local_producer
  Thread.new do
    miner = Miner.new
    until @should_stop
      begin
        new_block = miner.mine(@chain.blocks.last, @punch_queue.pop)
        @incoming_blocks << new_block

        # We need to let the consumer digest the block, otherwise we maybe mine the same block twice.
        # Notice that we feed the block into the network soon because adoption is also important.
        Thread.pass

        @buschtelefon_endpoint.feed(Buschtelefon::Gossip.new(new_block.to_h.to_json))
        @logger.info("local_producer") { "!" }
      rescue => e
        @logger.debug("local_producer") { "Mint block isn't valid: #{e.message}" }
        @logger.info("local_producer") { "F" }
      end
    end
  end
end
network_producer() click to toggle source
# File lib/lapidar/runner.rb, line 74
def network_producer
  Thread.new do
    @buschtelefon_endpoint.listen do |gossip, gossip_source|
      break if @should_stop

      begin
        incoming_json = JSON.parse(gossip.message, symbolize_names: true)

        @incoming_blocks << Block.new(
          number: incoming_json[:number].to_i,
          hash: incoming_json[:hash].to_s,
          nonce: incoming_json[:nonce].to_i,
          data: incoming_json[:data].to_s,
          created_at: incoming_json[:created_at].to_f
        )
      rescue JSON::ParserError, ArgumentError => e
        @logger.debug("network_producer") { "Incoming block isn't valid: #{e.message}" }
      end
    end
  end
end