lib/bitcoin/network/node.rb in bitcoin-ruby-0.0.5 vs lib/bitcoin/network/node.rb in bitcoin-ruby-0.0.6

- old
+ new

@@ -48,15 +48,20 @@ attr_accessor :relay_propagation DEFAULT_CONFIG = { :network => :bitcoin, - :listen => ["0.0.0.0", Bitcoin.network[:default_port]], + :listen => ["0.0.0.0", nil], :connect => [], :command => ["127.0.0.1", 9999], :storage => "utxo::sqlite://~/.bitcoin-ruby/<network>/blocks.db", + :announce => false, + :external_port => nil, :mode => :full, + :cache_head => true, + :index_nhash => false, + :index_p2sh_type => false, :dns => true, :epoll_limit => 10000, :epoll_user => nil, :addr_file => "~/.bitcoin-ruby/<network>/peers.json", :log => { @@ -100,12 +105,13 @@ end def set_store backend, config = @config[:storage].split('::') @store = Bitcoin::Storage.send(backend, { - db: config, mode: @config[:mode], cache_head: true, - skip_validation: @config[:skip_validation], + db: config, mode: @config[:mode], cache_head: @config[:cache_head], + skip_validation: @config[:skip_validation], index_nhash: @config[:index_nhash], + index_p2sh_type: @config[:index_p2sh_type], log_level: @config[:log][:storage]}, ->(locator) { peer = @connections.select(&:connected?).sample peer.send_getblocks(locator) }) @store.log.level = @config[:log][:storage] @@ -249,10 +255,35 @@ exit 1 end self.stop end + subscribe(:block) do |blk, depth| + next unless @store.in_sync? + @log.debug { "Relaying block #{blk.hash}" } + @connections.each do |conn| + next unless conn.connected? + conn.send_inv(:block, blk.hash) + end + end + + @store.subscribe(:block) do |blk, depth, chain| + if chain == 0 && blk.hash == @store.get_head.hash + @last_block_time = Time.now + push_notification(:block, [blk, depth]) + blk.tx.each {|tx| @unconfirmed.delete(tx.hash) } + end + getblocks if chain == 2 && @store.in_sync? + end + + @store.subscribe(:reorg) do |new_main, new_side| + @log.warn { "Reorg of #{new_side.size} blocks." } + new_main.each {|b| @log.debug { "new main: #{b}" } } + new_side.each {|b| @log.debug { "new side: #{b}" } } + push_notification(:reorg, [new_main, new_side]) + end + end end # connect to peer at given +host+ / +port+ def connect_peer host, port @@ -376,31 +407,17 @@ end while obj = @queue.shift begin if obj[0].to_sym == :block - if res = @store.send("new_#{obj[0]}", obj[1]) - if res[1] == 0 && obj[1].hash == @store.get_head.hash - @last_block_time = Time.now - push_notification(:block, [obj[1], res[0]]) - obj[1].tx.each {|tx| @unconfirmed.delete(tx.hash) } - end - getblocks if res[1] == 2 && @store.in_sync? - end + @store.new_block(obj[1]) else drop = @unconfirmed.size - @config[:max][:unconfirmed] + 1 drop.times { @unconfirmed.shift } if drop > 0 unless @unconfirmed[obj[1].hash] @unconfirmed[obj[1].hash] = obj[1] push_notification(:tx, [obj[1], 0]) - - if @notifiers[:output] - obj[1].out.each do |out| - address = Bitcoin::Script.new(out.pk_script).get_address - push_notification(:output, [obj[1].hash, address, out.value, 0]) - end - end end end rescue Bitcoin::Validation::ValidationError @log.warn { "ValidationError storing #{obj[0]} #{obj[1].hash}: #{$!.message}" } # File.open("./validation_error_#{obj[0]}_#{obj[1].hash}.bin", "w") {|f| @@ -454,25 +471,49 @@ @external_ips.group_by(&:dup).values.max_by(&:size).first rescue @config[:listen][0] end + # get the external port + # assume the same as local port if config option :external_port isn't given explicitly + def external_port + @config[:external_port] || @config[:listen][1] || Bitcoin.network[:default_port] + end + # push notification +message+ to +channel+ def push_notification channel, message @notifiers[channel.to_sym].push(message) if @notifiers[channel.to_sym] end # subscribe to notification +channel+. # available channels are: block, tx, output, connection. # see CommandHandler for details. def subscribe channel @notifiers[channel.to_sym] ||= EM::Channel.new - @notifiers[channel.to_sym].subscribe {|*data| yield(*data) } + @notifiers[channel.to_sym].subscribe do |*data| + begin + yield(*data) + rescue + p $!; puts *$@ + end + end end + def unsubscribe channel, id + @notifiers[channel.to_sym].unsubscribe(id) + end + # should the node accept new incoming connections? def accept_connections? - connections.select(&:incoming?).size >= config[:max][:connections_in] + connections.select(&:incoming?).size < config[:max][:connections_in] + end + + # get Addr object for our own server + def addr + @addr = Bitcoin::P::Addr.new + @addr.time, @addr.service, @addr.ip, @addr.port = + Time.now.tv_sec, (1 << 0), external_ip, external_port + @addr end end end