class Ciri::P2P::Server

P2P Server maintain connection, node discovery, rlpx handshake

Constants

DEFAULT_DIAL_RATIO
DEFAULT_MAX_PENDING_PEERS

Attributes

dial_scheduler[R]
dialer[R]
handshake[R]
local_address[R]
tcp_port[R]

Public Class Methods

new(private_key:, protocols:, bootnodes: [], node_name: 'Ciri', host: '127.0.0.1', tcp_port: 33033, udp_port: 33033, max_outgoing: 10, max_incoming:10, ping_interval_secs: 15, discovery_interval_secs: 15, dial_outgoing_interval_secs: 25) click to toggle source
# File lib/ciri/p2p/server.rb, line 56
def initialize(private_key:, protocols:, bootnodes: [],
               node_name: 'Ciri', host: '127.0.0.1',
               tcp_port: 33033, udp_port: 33033,
               max_outgoing: 10, max_incoming:10,
               ping_interval_secs: 15,
               discovery_interval_secs: 15,
               dial_outgoing_interval_secs: 25)
  @private_key = private_key
  @node_name = node_name
  # prepare handshake information
  @local_node_id = NodeID.new(@private_key)
  caps = protocols.map do |protocol|
    Cap.new(name: protocol.name, version: protocol.version)
  end
  @handshake = ProtocolHandshake.new(version: BASE_PROTOCOL_VERSION, name: @node_name, id: @local_node_id.id, caps: caps)
  @host = host
  @tcp_port = tcp_port
  @udp_port = udp_port
  @dialer = Dialer.new(private_key: private_key, handshake: @handshake)
  @peer_store = PeerStore.new
  @network_state = NetworkState.new(
    protocols: protocols,
    peer_store: @peer_store,
    local_node_id: @local_node_id,
    max_incoming: max_incoming,
    max_outgoing: max_outgoing,
    ping_interval_secs: ping_interval_secs)
  @bootnodes = bootnodes
  @discovery_interval_secs = discovery_interval_secs
  @dial_outgoing_interval_secs = dial_outgoing_interval_secs
end

Public Instance Methods

run() click to toggle source

return reactor to wait

# File lib/ciri/p2p/server.rb, line 98
def run
  # setup bootnodes
  @bootnodes.each do |node|
    @peer_store.add_bootnode(node)
  end

  # start server and services
  Async::Reactor.run do |task|
    # initialize protocols
    @network_state.initialize_protocols
    # wait sub tasks
    task.async do
      task.async do
        # Wait for server started listen
        # we use listened port to start DiscoveryService to allow 0 port
        task.sleep(0.5) until @local_address

        # start discovery service
        @discovery_service = Discovery::Service.new(
          peer_store: @peer_store,
          private_key: @private_key,
          host: @host, udp_port: @udp_port, tcp_port: @tcp_port,
          discovery_interval_secs: @discovery_interval_secs)
        task.async { @discovery_service.run }

        # start dial outgoing nodes
        @dial_scheduler = DialScheduler.new(
          @network_state,
          @dialer,
          dial_outgoing_interval_secs: @dial_outgoing_interval_secs)
        task.async {@dial_scheduler.run}
      end
      task.async {start_listen}
    end.wait
  end
end
start_listen(task: Async::Task.current) click to toggle source

start listen and accept clients

# File lib/ciri/p2p/server.rb, line 136
def start_listen(task: Async::Task.current)
  endpoint = Async::IO::Endpoint.tcp(@host, @tcp_port)
  endpoint.bind do |socket|
    @local_address = socket.local_address
    info("start accept connections -- listen on #{@local_address.getnameinfo.join(":")}")
    # update tcp_port if it is 0
    if @tcp_port.zero?
      @tcp_port = @local_address.ip_port
    end
    socket.listen(Socket::SOMAXCONN)
    loop do
      client, addrinfo = socket.accept
      c = Connection.new(client)
      c.encryption_handshake!(private_key: @private_key)
      remote_handshake = c.protocol_handshake!(handshake)
      @network_state.new_peer_connected(c, remote_handshake, direction: Peer::INCOMING)
    end
  end
end
to_node() click to toggle source
# File lib/ciri/p2p/server.rb, line 92
def to_node
  address = Address.new(ip: @host, tcp_port: tcp_port, udp_port: udp_port)
  Node.new(node_id: @local_node_id, addresses: [address])
end
udp_port() click to toggle source
# File lib/ciri/p2p/server.rb, line 88
def udp_port
  @discovery_service&.udp_port || @udp_port
end