net_plugin.cpp 18.1 KB
Newer Older
N
Nathan Hourt 已提交
1
#include <eos/chain/types.hpp>
N
Nathan Hourt 已提交
2 3 4

#include <eos/net_plugin/net_plugin.hpp>
#include <eos/net_plugin/protocol.hpp>
P
Phil Mesnier 已提交
5
#include <eos/chain/chain_controller.hpp>
P
Phil Mesnier 已提交
6
#include <eos/chain/exceptions.hpp>
N
Nathan Hourt 已提交
7 8 9 10 11

#include <fc/network/ip.hpp>
#include <fc/io/raw.hpp>
#include <fc/container/flat.hpp>
#include <fc/reflect/variant.hpp>
P
Phil Mesnier 已提交
12
#include <fc/crypto/rand.hpp>
N
Nathan Hourt 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

#include <boost/asio/ip/tcp.hpp>

namespace eos {
   using std::vector;
   using boost::asio::ip::tcp;
   using fc::time_point;
   using fc::time_point_sec;
   using eos::chain::transaction_id_type;
   namespace bip = boost::interprocess;

   using socket_ptr = std::shared_ptr<tcp::socket>;

struct node_transaction_state {
   transaction_id_type id;
   fc::time_point      received;
   fc::time_point_sec  expires;
   vector<char>        packed_transaction;
P
Phil Mesnier 已提交
31
   uint32_t            block_num = -1; /// block transaction was included in
N
Nathan Hourt 已提交
32 33 34 35 36 37 38 39 40
   bool                validated = false; /// whether or not our node has validated it
};


/**
 *  Index by id
 *  Index by is_known, block_num, validated_time, this is the order we will broadcast
 *  to peer.
 *  Index by is_noticed, validated_time
P
Phil Mesnier 已提交
41
 *
N
Nathan Hourt 已提交
42 43 44 45
 */
struct transaction_state {
   transaction_id_type id;
   bool                is_known_by_peer = false; ///< true if we sent or received this trx to this peer or received notice from peer
P
Phil Mesnier 已提交
46
   bool                is_noticed_to_peer = false; ///< have we sent peer notice we know it (true if we receive from this peer)
P
Phil Mesnier 已提交
47
   uint32_t            block_num = -1; ///< the block number the transaction was included in
N
Nathan Hourt 已提交
48 49 50 51 52 53 54 55 56 57 58 59
   time_point          validated_time; ///< infinity for unvalidated
   time_point          requested_time; /// incase we fetch large trx
};

typedef multi_index_container<
   transaction_state,
   indexed_by<
      ordered_unique< tag<by_id>, member<transaction_state, transaction_id_type, &transaction_state::id > >
   >
> transaction_state_index;

/**
P
Phil Mesnier 已提交
60
 *
N
Nathan Hourt 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
 */
struct block_state {
   block_id_type id;
   bool          is_known;
   bool          is_noticed_to_peer;
   time_point    requested_time;
};

typedef multi_index_container<
   block_state,
   indexed_by<
      ordered_unique< tag<by_id>, member<block_state, block_id_type, &block_state::id > >
   >
> block_state_index;

/**
 * Index by start_block
 */
struct sync_state {
P
Phil Mesnier 已提交
80 81 82
   uint32_t     start_block = 0;
   uint32_t     end_block = 0;
   uint32_t     last = 0; ///< last sent or received
N
Nathan Hourt 已提交
83 84 85 86 87 88 89
   time_point   start_time;; ///< time request made or received
};

struct by_start_block;
typedef multi_index_container<
   sync_state,
   indexed_by<
P
Phil Mesnier 已提交
90
      ordered_unique< tag<by_start_block>, member<sync_state, uint32_t, &sync_state::start_block > >
N
Nathan Hourt 已提交
91 92 93 94
   >
> sync_request_index;

class connection {
P
Phil Mesnier 已提交
95 96 97
public:
  connection( socket_ptr s )
    : socket(s)
P
Phil Mesnier 已提交
98
  {
N
Nathan Hourt 已提交
99 100 101
         wlog( "created connection" );
         pending_message_buffer.resize( 1024*1024*4 );
      }
P
Phil Mesnier 已提交
102

N
Nathan Hourt 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116
      ~connection() {
         wlog( "released connection" );
      }

      block_state_index              block_state;
      transaction_state_index        trx_state;
      sync_request_index             in_sync_state;
      sync_request_index             out_sync_state;
      socket_ptr                     socket;

      uint32_t                       pending_message_size;
      vector<char>                   pending_message_buffer;

      handshake_message              last_handshake;
P
Phil Mesnier 已提交
117
      std::deque<net_message>        out_queue;
N
Nathan Hourt 已提交
118 119 120 121 122

      void send( const net_message& m ) {
         out_queue.push_back( m );
         if( out_queue.size() == 1 )
            send_next_message();
123 124 125
         else {
           dlog ("send: out_queue size = ${s}", ("s",out_queue.size()));
         }
N
Nathan Hourt 已提交
126 127
      }

128

N
Nathan Hourt 已提交
129
      void send_next_message() {
P
Phil Mesnier 已提交
130 131 132 133 134 135
        if( !out_queue.size() ) {
          if (out_sync_state.size() > 0) {
            write_block_backlog();
          }
          return;
        }
N
Nathan Hourt 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

         auto& m = out_queue.front();

         vector<char> buffer;
         uint32_t size = fc::raw::pack_size( m );
         buffer.resize(  size + sizeof(uint32_t) );
         fc::datastream<char*> ds( buffer.data(), buffer.size() );
         ds.write( (char*)&size, sizeof(size) );
         fc::raw::pack( ds, m );

         boost::asio::async_write( *socket, boost::asio::buffer( buffer.data(), buffer.size() ),
            [this,buf=std::move(buffer)]( boost::system::error_code ec, std::size_t bytes_transferred ) {
               if( ec ) {
                  elog( "Error sending message: ${msg}", ("msg",ec.message() ) );
               } else  {
                  out_queue.pop_front();
                  send_next_message();
               }
         });
      }
P
Phil Mesnier 已提交
156 157 158 159 160 161 162 163 164 165

     void write_block_backlog ( ) {
      try {
        if (out_sync_state.size() > 0) {
          chain_controller& cc = app().find_plugin<chain_plugin>()->chain();
          auto ss = out_sync_state.begin();
          for (uint32_t num = ss->last + 1;
               num <= ss->end_block; num++) {
            fc::optional<signed_block> sb = cc.fetch_block_by_number(num);
            if (sb) {
166
              dlog("write backlog, block #${num}",("num",num));
P
Phil Mesnier 已提交
167 168 169 170 171 172 173 174 175 176 177 178
              send( *sb );
            }
            ss.get_node()->value().last = num;
          }
          out_sync_state.erase(0);
        }
      } catch ( ... ) {
         wlog( "write loop exception" );
      }
   }


P
Phil Mesnier 已提交
179
}; // class connection
N
Nathan Hourt 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195



class net_plugin_impl {
   public:
   unique_ptr<tcp::acceptor> acceptor;

   tcp::endpoint listen_endpoint;
   tcp::endpoint public_endpoint;

   vector<string> seed_nodes;

   std::set<socket_ptr>          pending_connections;
   std::set< connection* >       connections;
   bool                          done = false;

P
Phil Mesnier 已提交
196 197 198 199
   fc::optional<handshake_message> hello;
   std::string user_agent_name;
  chain_plugin* chain_plug;

P
Phil Mesnier 已提交
200

P
Phil Mesnier 已提交
201 202 203
   void connect( const string& peer_addr ) {
     auto host = peer_addr.substr( 0, peer_addr.find(':') );
     auto port = peer_addr.substr( host.size()+1, host.size() );
N
Nathan Hourt 已提交
204
     idump((host)(port));
P
Phil Mesnier 已提交
205
     auto resolver = std::make_shared<tcp::resolver>( std::ref( app().get_io_service() ) );
N
Nathan Hourt 已提交
206
     tcp::resolver::query query( tcp::v4(), host.c_str(), port.c_str() );
P
Phil Mesnier 已提交
207
     // Note: need to add support for IPv6 too
N
Nathan Hourt 已提交
208

P
Phil Mesnier 已提交
209
     resolver->async_resolve( query,
P
Phil Mesnier 已提交
210
       [resolver,peer_addr,this]( const boost::system::error_code& err, tcp::resolver::iterator endpoint_itr ){
N
Nathan Hourt 已提交
211 212 213
         if( !err ) {
           connect( resolver, endpoint_itr );
         } else {
P
Phil Mesnier 已提交
214
           elog( "Unable to resolve ${peer_addr}: ${error}", ( "peer_addr", peer_addr )("error", err.message() ) );
N
Nathan Hourt 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227 228
         }
     });
   }

   void connect( std::shared_ptr<tcp::resolver> resolver, tcp::resolver::iterator endpoint_itr ) {
     auto sock = std::make_shared<tcp::socket>( std::ref( app().get_io_service() ) );
     pending_connections.insert( sock );

     auto current_endpoint = *endpoint_itr;
     ++endpoint_itr;
     sock->async_connect( current_endpoint,
        [sock,resolver,endpoint_itr,this]( const boost::system::error_code& err ) {
           if( !err ) {
              pending_connections.erase( sock );
P
Phil Mesnier 已提交
229
              start_session( new connection( sock ) );
N
Nathan Hourt 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
           } else {
              if( endpoint_itr != tcp::resolver::iterator() ) {
                connect( resolver, endpoint_itr );
              }
           }
        }
     );
   }

   /**
    * This thread performs high level coordination among multiple connections and
    * ensures connections are cleaned up, reconnected, etc.
    */
   void network_loop() {
   try {
      ilog( "starting network loop" );
      while( !done ) {
         for( auto itr = connections.begin(); itr != connections.end(); ) {
            auto con = *itr;
            if( !con->socket->is_open() )  {
               close(con);
               itr = connections.begin();
               continue;
            }
            ++itr;
         }
      }
      ilog("network loop done");
   } FC_CAPTURE_AND_RETHROW() }

P
Phil Mesnier 已提交
260

P
Phil Mesnier 已提交
261 262 263 264 265 266
  void init_handshake () {
    if (!hello) {
      hello = handshake_message();
    }

    hello->network_version = 0;
P
Phil Mesnier 已提交
267
    chain_plug->get_chain_id(hello->chain_id);
P
Phil Mesnier 已提交
268
    fc::rand_pseudo_bytes(hello->node_id.data(), hello->node_id.data_size());
P
Phil Mesnier 已提交
269 270 271 272 273 274 275 276 277 278
#if defined( __APPLE__ )
    hello->os = "osx";
#elif defined( __linux__ )
    hello->os = "linux";
#elif defined( _MSC_VER )
    hello->os = "win32";
#else
    hello->os = "other";
#endif
    hello->agent = user_agent_name;
P
Phil Mesnier 已提交
279
    update_handshake ();
P
Phil Mesnier 已提交
280 281 282
  }

  void update_handshake () {
P
Phil Mesnier 已提交
283 284 285 286 287 288 289 290 291 292 293
    try {
      hello->last_irreversible_block_id = chain_plug->chain().get_block_id_for_num
        (hello->last_irreversible_block_num = chain_plug->chain().last_irreversible_block_num());
      ilog ("update_handshake my libnum = ${n}",("n",hello->last_irreversible_block_num));
    }
    catch (const unknown_block_exception &ex) {
      hello->last_irreversible_block_id = fc::sha256::hash(0);
      hello->last_irreversible_block_num = 0;
      ilog ("update_handshake my libnum = ${n}",("n",hello->last_irreversible_block_num));

    }
P
Phil Mesnier 已提交
294 295
  }

N
Nathan Hourt 已提交
296 297 298
   void start_session( connection* con ) {
     connections.insert( con );
     start_read_message( *con );
P
Phil Mesnier 已提交
299

P
Phil Mesnier 已提交
300 301 302 303 304 305 306
     if (hello.valid()) {
       update_handshake ();
     } else {
       init_handshake ();
     }

     con->send( *hello );
P
Phil Mesnier 已提交
307

P
Phil Mesnier 已提交
308 309
     //     con->readloop_complete  = bf::async( [=](){ read_loop( con ); } );
     //     con->writeloop_complete = bf::async( [=](){ write_loop con ); } );
N
Nathan Hourt 已提交
310 311 312 313 314 315
   }

   void start_listen_loop() {
      auto socket = std::make_shared<tcp::socket>( std::ref( app().get_io_service() ) );
      acceptor->async_accept( *socket, [socket,this]( boost::system::error_code ec ) {
         if( !ec ) {
P
Phil Mesnier 已提交
316
           start_session( new connection( socket ) );
P
Phil Mesnier 已提交
317
           start_listen_loop();
N
Nathan Hourt 已提交
318 319 320 321 322 323 324 325
         } else {
            elog( "Error accepting connection: ${m}", ("m", ec.message() ) );
         }
      });
   }

   void start_read_message( connection& c ) {
      c.pending_message_size = 0;
P
Phil Mesnier 已提交
326
      boost::asio::async_read( *c.socket, boost::asio::buffer((char*)&c.pending_message_size,sizeof(c.pending_message_size)),
N
Nathan Hourt 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
        [&]( boost::system::error_code ec, std::size_t bytes_transferred ) {
           ilog( "read size handler..." );
           if( !ec ) {
              if( c.pending_message_size <= c.pending_message_buffer.size() ) {
                start_reading_pending_buffer( c );
                return;
              } else {
                elog( "Received a message that was too big" );
              }
           } else {
            elog( "Error reading message from connection: ${m}", ("m", ec.message() ) );
           }
           close( &c );
        }
      );
   }
P
Phil Mesnier 已提交
343

P
Phil Mesnier 已提交
344 345 346 347 348 349 350
  template<typename T>
  void send_all (const T &msg) {
    for (auto &c : connections) {
      c->send(msg);
    }
  }

351
  void handle_message (connection &c, const handshake_message &msg) {
P
Phil Mesnier 已提交
352 353 354
    if (!hello) {
      init_handshake();
    }
P
Phil Mesnier 已提交
355 356 357
    ilog ("got a handshake message");
    if (msg.node_id == hello->node_id) {
      elog ("Self connection detected. Closing connection");
P
Phil Mesnier 已提交
358 359 360
      close(&c);
      return;
    }
P
Phil Mesnier 已提交
361 362 363 364 365 366 367 368 369 370 371 372
    if (msg.chain_id != hello->chain_id) {
      elog ("Peer on a different chain. Closing connection");
      close (&c);
      return;
    }
    if (msg.network_version != hello->network_version) {
      elog ("Peer network id does not match ");
      close (&c);
      return;
    }
    chain_controller& cc = chain_plug->chain();
    uint32_t head = cc.head_block_num ();
P
Phil Mesnier 已提交
373
    ilog ("My head block = ${h} their lib = ${lib}", ("h",head)("lib", msg.last_irreversible_block_num));
P
Phil Mesnier 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    if ( msg.last_irreversible_block_num > head) {
      uint32_t delta = msg.last_irreversible_block_num - head;
      uint32_t count = connections.size();
      uint32_t span = delta / count;
      uint32_t lastSpan = delta - (span * (count-1));
      ilog ("peer is ahead of head by ${d}, count = ${c}, span = ${s}, lastspan = ${ls} ",
            ("d",delta)("c",count)("s",span)("ls",lastSpan));
      for (auto &cx: connections) {
        if (--count == 0) {
          span = lastSpan;
        }
        sync_state req = {head+1, head+span, 0, time_point::now() };
        cx->in_sync_state.insert (req);
        sync_request_message srm = {req.start_block, req.end_block };
        cx->send (srm);
        head += span;
P
Phil Mesnier 已提交
390 391
      }

P
Phil Mesnier 已提交
392
    }
P
Phil Mesnier 已提交
393

P
Phil Mesnier 已提交
394 395 396 397
    c.last_handshake = msg;
  }


398
  void handle_message (connection &c, const peer_message &msg) {
P
Phil Mesnier 已提交
399 400 401
    ilog ("got a peer message");
  }

402
  void handle_message (connection &c, const notice_message &msg) {
P
Phil Mesnier 已提交
403 404 405
    ilog ("got a notice message");
  }

406
  void handle_message (connection &c, const sync_request_message &msg) {
P
Phil Mesnier 已提交
407 408 409 410
    ilog ("got a sync request message for blocks ${s} to ${e}", ("s",msg.start_block)("e", msg.end_block));
    sync_state req = {msg.start_block,msg.end_block,0,time_point::now()};
    c.out_sync_state.insert (req);
    c.write_block_backlog ();
P
Phil Mesnier 已提交
411 412
  }

413
  void handle_message (connection &c, const block_summary_message &msg) {
P
Phil Mesnier 已提交
414 415 416
    ilog ("got a block summary message");
  }

417
  void handle_message (connection &c, const SignedTransaction &msg) {
P
Phil Mesnier 已提交
418
    ilog ("got a SignedTransacton");
P
Phil Mesnier 已提交
419
    chain_plug->accept_transaction (msg);
P
Phil Mesnier 已提交
420 421
  }

422
  void handle_message (connection &c, const signed_block &msg) {
P
Phil Mesnier 已提交
423
    uint32_t bn = msg.block_num();
424
    dlog ("got a signed_block, num = ${n}", ("n", bn));
P
Phil Mesnier 已提交
425 426 427
    chain_controller &cc = chain_plug->chain();

    if (cc.is_known_block(msg.id())) {
428
      dlog ("block id ${id} is known", ("id", msg.id()) );
P
Phil Mesnier 已提交
429 430 431
      return;
    }
    uint32_t num = msg.block_num();
432

P
Phil Mesnier 已提交
433
    bool syncing = false;
P
Phil Mesnier 已提交
434 435 436 437 438
    for (auto &ss: c.in_sync_state) {
      if (num >= ss.end_block) {
        continue;
      }
      const_cast<sync_state&>(ss).last = num;
P
Phil Mesnier 已提交
439
      syncing = true;
P
Phil Mesnier 已提交
440 441
      break;
    }
442 443
    if (!syncing) {
      try {
444 445
        block_id_type id = cc.get_block_id_for_num (num-1);
        dlog ("got the prevous block id = ${id}",("id",id));
446 447
      }
      catch (const unknown_block_exception &ex) {
448 449 450
        uint32_t head = cc.head_block_num();
        dlog ("block num ${n} is not known, head = ${h}",("n",(num-1))("h",head));
        sync_state req = {head+1, num-1, 0, time_point::now() };
451 452 453 454 455 456 457 458
        c.in_sync_state.insert (req);
        sync_request_message srm = {req.start_block, req.end_block };
        c.send (srm);

        syncing = true;
      }

    }
P
Phil Mesnier 已提交
459
    chain_plug->accept_block(msg, syncing);
P
Phil Mesnier 已提交
460 461
  }

P
Phil Mesnier 已提交
462 463 464 465 466 467

  struct msgHandler : public fc::visitor<void> {
    net_plugin_impl &impl;
    connection &c;
    msgHandler (net_plugin_impl &imp, connection &conn) : impl(imp), c(conn) {}

468 469
    template <typename T>
    void operator()(const T &msg) const
P
Phil Mesnier 已提交
470 471 472 473 474 475
    {
      impl.handle_message (c, msg);
    }
  };


P
Phil Mesnier 已提交
476 477
  void start_reading_pending_buffer( connection& c ) {
      boost::asio::async_read( *c.socket, boost::asio::buffer(c.pending_message_buffer.data(), c.pending_message_size ),
N
Nathan Hourt 已提交
478 479 480 481 482 483 484
        [&]( boost::system::error_code ec, std::size_t bytes_transferred ) {
           ilog( "read buffer handler..." );
           if( !ec ) {
            try {
               auto msg = fc::raw::unpack<net_message>( c.pending_message_buffer );
               ilog( "received message of size: ${s}", ("s",bytes_transferred) );
               start_read_message( c );
P
Phil Mesnier 已提交
485

P
Phil Mesnier 已提交
486 487
               msgHandler m(*this, c);
               msg.visit(m);
N
Nathan Hourt 已提交
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
               return;
            } catch ( const fc::exception& e ) {
              edump((e.to_detail_string() ));
            }
           } else {
            elog( "Error reading message from connection: ${m}", ("m", ec.message() ) );
           }
           close( &c );
        }
      );
   }


   void close( connection* c ) {
      ilog( "close ${c}", ("c",int64_t(c)));
      if( c->socket )
         c->socket->close();
      connections.erase( c );
      delete c;
   }

P
Phil Mesnier 已提交
509
}; // class net_plugin_impl
N
Nathan Hourt 已提交
510 511 512 513 514 515 516 517

net_plugin::net_plugin()
:my( new net_plugin_impl ) {
}

net_plugin::~net_plugin() {
}

P
Phil Mesnier 已提交
518
void net_plugin::set_program_options( options_description& cli, options_description& cfg )
N
Nathan Hourt 已提交
519 520 521 522 523
{
   cfg.add_options()
         ("listen-endpoint", bpo::value<string>()->default_value( "127.0.0.1:9876" ), "The local IP address and port to listen for incoming connections.")
         ("remote-endpoint", bpo::value< vector<string> >()->composing(), "The IP address and port of a remote peer to sync with.")
         ("public-endpoint", bpo::value<string>()->default_value( "0.0.0.0:9876" ), "The public IP address and port that should be advertized to peers.")
P
Phil Mesnier 已提交
524
     ("agent-name", bpo::value<string>()->default_value("EOS Test Agent"), "The name supplied to identify this node amongst the peers.")
N
Nathan Hourt 已提交
525 526 527 528 529 530 531 532 533
         ;
}

void net_plugin::plugin_initialize( const variables_map& options ) {
   ilog("Initialize net plugin");
   if( options.count( "listen-endpoint" ) ) {
      auto lipstr = options.at("listen-endpoint").as< string >();
      auto fcep   = fc::ip::endpoint::from_string( lipstr );
      my->listen_endpoint = tcp::endpoint( boost::asio::ip::address_v4::from_string( (string)fcep.get_address() ), fcep.port() );
P
Phil Mesnier 已提交
534

N
Nathan Hourt 已提交
535 536 537 538 539 540 541
      ilog( "configured net to listen on ${ep}", ("ep", fcep) );

      my->acceptor.reset( new tcp::acceptor( app().get_io_service() ) );
   }
   if( options.count( "remote-endpoint" ) ) {
      my->seed_nodes = options.at( "remote-endpoint" ).as< vector<string> >();
   }
P
Phil Mesnier 已提交
542 543 544
   if (options.count("agent-name")) {
     my->user_agent_name = options.at ("agent-name").as< string > ();
   }
P
Phil Mesnier 已提交
545
   my->chain_plug = app().find_plugin<chain_plugin>();
N
Nathan Hourt 已提交
546 547
}

P
Phil Mesnier 已提交
548
  void net_plugin::plugin_startup() {
N
Nathan Hourt 已提交
549 550
  // boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
  if( my->acceptor ) {
P
Phil Mesnier 已提交
551

N
Nathan Hourt 已提交
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
      my->acceptor->open(my->listen_endpoint.protocol());
      my->acceptor->set_option(tcp::acceptor::reuse_address(true));
      my->acceptor->bind(my->listen_endpoint);
      my->acceptor->listen();

      my->start_listen_loop();
  }

  for( auto seed_node : my->seed_nodes ) {
     my->connect( seed_node );
  }
}

void net_plugin::plugin_shutdown() {
try {
   ilog( "shutdown.." );
   my->done = true;
   if( my->acceptor ) {
      ilog( "close acceptor" );
      my->acceptor->close();

      ilog( "close connections ${s}", ("s",my->connections.size()) );
      auto cons = my->connections;
P
Phil Mesnier 已提交
575
      for( auto con : cons )
N
Nathan Hourt 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588
         con->socket->close();

      while( my->connections.size() ) {
         auto c = *my->connections.begin();
         my->close( c );
      }

      idump((my->connections.size()));
      my->acceptor.reset(nullptr);
   }
   ilog( "exit shutdown" );
} FC_CAPTURE_AND_RETHROW() }

P
Phil Mesnier 已提交
589 590 591 592
  void net_plugin::broadcast_block (const chain::signed_block &sb) {
    my->send_all (sb);
  }

N
Nathan Hourt 已提交
593
}