bitcoin_node 5.02 KB
#!/usr/bin/env ruby
$:.unshift( File.expand_path("../../lib", __FILE__) )

require 'bitcoin'
require 'optparse'
require 'fileutils'
Bitcoin.require_dependency :eventmachine
Bitcoin.require_dependency :json

defaults = Bitcoin::Network::Node::DEFAULT_CONFIG

options = Bitcoin::Config.load(defaults, :blockchain)

optparse = OptionParser.new do |opts|
  opts.banner = "Usage: bitcoin_node [options]"

  opts.separator("\nAvailable options:\n")

  opts.on("-c", "--config FILE",
    "Config file (default: #{Bitcoin::Config::CONFIG_PATHS})") do |file|
    options = Bitcoin::Config.load_file(options, file, :blockchain)
  end

  opts.on("-n", "--network [NETWORK]",
    "User Network (default: #{options[:network]})") do |network|
    options[:network] = network
  end

  opts.on("--command [HOST:PORT]",
          "Command socket (default: #{options[:command].join(':')})") do |command|
    options[:command] = command.split(":")
  end

  opts.on("-l", "--listen [HOST:PORT]",
    "Listen address/port (default: #{options[:listen].join(':')})") do |listen|
    options[:listen] = listen.split(":")
  end

  opts.on("--connect [HOST:PORT]",
    "Hosts to connect to (default: #{options[:connect].map{|c|c.join(':')}.join(',')})") do |connect|
    connect.split(",").each do |host|
      options[:connect] << host.split(":")
    end
  end

  opts.on("-s", "--storage [BACKEND::CONFIG]",
    "Use storage backend (default: #{options[:storage]})") do |storage|
    options[:storage] = storage
  end

  opts.on("--skip-validation", "Skip validation of blocks and transactions") do
    options[:skip_validation] = true
  end

  opts.on("--check-blocks COUNT",
          "Check consistency of COUNT latest blocks; -1 for all (default: 1000)") do |check|
    options[:check_blocks] = check.to_i
  end

  opts.on("--ho", "--headers-only",
    "Download only block headers") do
    options[:headers_only] = true
  end

  opts.on("-d", "--dns", "Use DNS seeds (default)") do
    options[:dns] = true
  end

  opts.on("--nd", "--no-dns", "Don't use DNS seeds") do
    options[:dns] = false
  end

  opts.on("--epoll", "Enable epoll support") do
    options[:epoll] = true
  end

  opts.on("--epoll-limit [NUM]",
    "Increase socket descriptor limit to NUM") do |num|
    options[:epoll_limit] = num.to_i
  end

  opts.on("--epoll-user [NAME]",
    "Set effective user after increasing socket descriptor limit") do |user|
    options[:epoll_user] = user
  end

  opts.on("--mco", "--max-connections-out COUNT", "Maximum number of outgoing connections (default: #{options[:max][:connections_out]})") do |count|
    options[:max][:connections_out] = count.to_i
  end

  opts.on("--mci", "--max-connections-in COUNT", "Maximum number of incoming connections (default: #{options[:max][:connections_in]})") do |count|
    options[:max][:connections_in] = count.to_i
  end

  [:addr, :queue, :inv, :unconfirmed].each do |name|
    opts.on("--m#{name.to_s[0]}", "--max-#{name} [COUNT]",
      "Max #{name} (default: #{options[:max][name]})") do |count|
      options[:max][name] = count.to_i
    end
  end

  [:queue, :inv_queue, :blocks, :addrs, :connect].each do |name|
    opts.on("--i#{name.to_s[0]}", "--interval-#{name} [SECONDS]",
      "Interval for #{name} worker (default: #{options[:intervals][name]})") do |sec|
      options[:intervals][name] = sec.to_i
    end
  end

  [:network, :storage].each do |name|
    opts.on("--l#{name.to_s[0]}", "--log-#{name} [LEVEL]",
      "Log level for #{name} (default: #{options[:log][name]})") do |level|
      options[:log][name] = level.to_sym
    end
  end

  opts.on("--import DIR", "Import blk*.dat files from DIR") do |dir|
    options[:import] = dir
  end

  opts.on("-v", "--verbose", "Set all loggers to debug") do
    options[:log].each_key {|k| options[:log][k] = :debug }
  end

  opts.on("-q", "--quiet", "Set all loggers to warn") do
    options[:log].each_key {|k| options[:log][k] = :warn }
  end

  opts.on( '-h', '--help', 'Display this screen' ) do
    puts opts; exit
  end
end

optparse.parse!

Bitcoin.network = options[:network]
FileUtils.mkdir_p File.join(ENV['HOME'], ".bitcoin-ruby/#{Bitcoin.network_name}")

if ARGV.any?
  EM.run do
    Bitcoin::Network::CommandClient.connect(*options[:command]) do
      on_response do |cmd, data|
        unless cmd == "monitor"
          puts JSON.pretty_generate data
          EM.stop
        end
      end
      on_block do |block, depth|
        puts "block: #{block['hash']} (#{depth})"
      end
      on_tx do |tx, confirmations|
        puts "tx(#{confirmations}): #{tx['hash']}"
      end
      on_output do |tx_hash, address, value, confirmations|
        puts "output(#{confirmations}): tx #{tx_hash[0..8]}: #{address} received #{value.to_f / 1e8} BTC"
      end
      on_connection do |type, host|
        if type == "connected"
          puts "Connected: #{host['host']}:#{host['port']}"
        else
          puts "Disconnected: #{host.inspect}"
        end
      end
      on_connected do
        request(ARGV[0], *(ARGV[1] || "").split(" "))
      end
    end
  end
else
  node = Bitcoin::Network::Node.new(options)
  node.run
end