Example #1
0
int main(int argc, char** argv)
{
  std::queue<fc::ip::endpoint> nodes_to_visit;
  std::set<fc::ip::endpoint> nodes_to_visit_set;
  std::set<fc::ip::endpoint> nodes_already_visited;

  if ( argc < 3 ) {
     std::cerr << "Usage: " << argv[0] << " <chain-id> <seed-addr> [<seed-addr> ...]\n";
     exit(1);
  }

  const graphene::chain::chain_id_type chain_id( argv[1] );
  for ( int i = 2; i < argc; i++ )
  {
     std::string ep(argv[i]);
     uint16_t port;
     auto pos = ep.find(':');
     if (pos > 0)
        port = boost::lexical_cast<uint16_t>( ep.substr( pos+1, ep.size() ) );
     else
        port = 1776;
     for (const auto& addr : fc::resolve( ep.substr( 0, pos > 0 ? pos : ep.size() ), port ))
        nodes_to_visit.push( addr );
  }

  fc::path data_dir = fc::temp_directory_path() / ("network_map_" + (fc::string) chain_id);
  fc::create_directories(data_dir);

  fc::ip::endpoint seed_node1 = nodes_to_visit.front();

  fc::ecc::private_key my_node_id = fc::ecc::private_key::generate();
  std::map<graphene::net::node_id_t, graphene::net::address_info> address_info_by_node_id;
  std::map<graphene::net::node_id_t, std::vector<graphene::net::address_info> > connections_by_node_id;
  std::vector<std::shared_ptr<peer_probe>> probes;

  while (!nodes_to_visit.empty() || !probes.empty())
  {
    while (!nodes_to_visit.empty())
    {
       fc::ip::endpoint remote = nodes_to_visit.front();
       nodes_to_visit.pop();
       nodes_to_visit_set.erase( remote );
       nodes_already_visited.insert( remote );

       try
       {
          std::shared_ptr<peer_probe> probe(new peer_probe());
          probe->start(remote, my_node_id, chain_id);
          probes.emplace_back( std::move( probe ) );
       }
       catch (const fc::exception&)
       {
          std::cerr << "Failed to connect " << fc::string(remote) << " - skipping!" << std::endl;
       }
    }

    if (!probes.empty())
    {
       fc::yield();
       std::vector<std::shared_ptr<peer_probe>> running;
       for ( auto& probe : probes ) {
          if (probe->_probe_complete_promise->error())
          {
             std::cerr << fc::string(probe->_remote) << " ran into an error!\n";
             continue;
          }
          if (!probe->_probe_complete_promise->ready())
          {
             running.push_back( probe );
             continue;
          }

          if( probe->_node_id.valid() )
          {
             graphene::net::address_info this_node_info;
             this_node_info.direction = graphene::net::peer_connection_direction::outbound;
             this_node_info.firewalled = graphene::net::firewalled_state::not_firewalled;
             this_node_info.remote_endpoint = probe->_remote;
             this_node_info.node_id = probe->_node_id;

             connections_by_node_id[this_node_info.node_id] = probe->_peers;
             if (address_info_by_node_id.find(this_node_info.node_id) == address_info_by_node_id.end())
                address_info_by_node_id[this_node_info.node_id] = this_node_info;
          }

          for (const graphene::net::address_info& info : probe->_peers)
          {
             if (nodes_already_visited.find(info.remote_endpoint) == nodes_already_visited.end() &&
                 info.firewalled == graphene::net::firewalled_state::not_firewalled &&
                 nodes_to_visit_set.find(info.remote_endpoint) == nodes_to_visit_set.end())
             {
                nodes_to_visit.push(info.remote_endpoint);
                nodes_to_visit_set.insert(info.remote_endpoint);
             }
             if (address_info_by_node_id.find(info.node_id) == address_info_by_node_id.end())
                address_info_by_node_id[info.node_id] = info;
          }
       }
       probes = std::move( running );
       std::cout << address_info_by_node_id.size() << " checked, "
                 << probes.size() << " active, "
                 << nodes_to_visit.size() << " to do\n";
    }
  }

  graphene::net::node_id_t seed_node_id;
  std::set<graphene::net::node_id_t> non_firewalled_nodes_set;
  for (const auto& address_info_for_node : address_info_by_node_id)
  {
    if (address_info_for_node.second.remote_endpoint == seed_node1)
      seed_node_id = address_info_for_node.first;
    if (address_info_for_node.second.firewalled == graphene::net::firewalled_state::not_firewalled)
      non_firewalled_nodes_set.insert(address_info_for_node.first);
  }
  std::set<graphene::net::node_id_t> seed_node_connections;
  for (const graphene::net::address_info& info : connections_by_node_id[seed_node_id])
    seed_node_connections.insert(info.node_id);
  std::set<graphene::net::node_id_t> seed_node_missing_connections;
  std::set_difference(non_firewalled_nodes_set.begin(), non_firewalled_nodes_set.end(),
                      seed_node_connections.begin(), seed_node_connections.end(),
                      std::inserter(seed_node_missing_connections, seed_node_missing_connections.end()));
  seed_node_missing_connections.erase(seed_node_id);

  std::ofstream dot_stream((data_dir / "network_graph.dot").string().c_str());

  dot_stream << "graph G {\n";
  dot_stream << "  // Total " << address_info_by_node_id.size() << " nodes, firewalled: " << (address_info_by_node_id.size() - non_firewalled_nodes_set.size())
                              << ", non-firewalled: " << non_firewalled_nodes_set.size() << "\n";
  dot_stream << "  // Seed node is " << (std::string)address_info_by_node_id[seed_node_id].remote_endpoint << " id: " << fc::variant( seed_node_id, 1 ).as_string() << "\n";
  dot_stream << "  // Seed node is connected to " << connections_by_node_id[seed_node_id].size() << " nodes\n";
  dot_stream << "  // Seed node is missing connections to " << seed_node_missing_connections.size() << " non-firewalled nodes:\n";
  for (const graphene::net::node_id_t& id : seed_node_missing_connections)
    dot_stream << "  //           " << (std::string)address_info_by_node_id[id].remote_endpoint << "\n";

  dot_stream << "  layout=\"circo\";\n";

  for (const auto& address_info_for_node : address_info_by_node_id)
  {
    dot_stream << "  \"" << fc::variant( address_info_for_node.first, 1 ).as_string() << "\"[label=\"" << (std::string)address_info_for_node.second.remote_endpoint << "\"";
    if (address_info_for_node.second.firewalled != graphene::net::firewalled_state::not_firewalled)
      dot_stream << ",shape=rectangle";
    dot_stream << "];\n";
  }
  for (auto& node_and_connections : connections_by_node_id)
    for (const graphene::net::address_info& this_connection : node_and_connections.second)
      dot_stream << "  \"" << fc::variant( node_and_connections.first, 2 ).as_string() << "\" -- \"" << fc::variant( this_connection.node_id, 1 ).as_string() << "\";\n";

  dot_stream << "}\n";

  return 0;
}
Example #2
0
int main(int argc, char** argv)
{
  std::queue<fc::ip::endpoint> nodes_to_visit;
  std::set<fc::ip::endpoint> nodes_to_visit_set;
  std::set<fc::ip::endpoint> nodes_already_visited;

  fc::path data_dir = fc::temp_directory_path() / "map_bts_network";
  fc::create_directories(data_dir);

  bts::client::config default_client_config;
  for (const std::string default_peer : default_client_config.default_peers)
    nodes_to_visit.push(fc::ip::endpoint::from_string(default_peer));
  fc::ip::endpoint seed_node1 = nodes_to_visit.front();

  fc::ecc::private_key my_node_id = fc::ecc::private_key::generate();
  bts::blockchain::chain_database_ptr chain_db = std::make_shared<bts::blockchain::chain_database>();
  chain_db->open(data_dir / "chain", fc::optional<fc::path>("C:/Users/Administrator/AppData/Local/Temp/map_bts_network/genesis.json"));

  std::map<bts::net::node_id_t, bts::net::address_info> address_info_by_node_id;
  std::map<bts::net::node_id_t, std::vector<bts::net::address_info> > connections_by_node_id;
  //std::map<bts::net::node_id_t, fc::ip::endpoint> all_known_nodes;

  while (!nodes_to_visit.empty())
  {
    bts::net::address_info this_node_info;
    this_node_info.direction = bts::net::peer_connection_direction::outbound;
    this_node_info.firewalled = bts::net::firewalled_state::not_firewalled;

    this_node_info.remote_endpoint = nodes_to_visit.front();;
    nodes_to_visit.pop();
    nodes_to_visit_set.erase(this_node_info.remote_endpoint);
    nodes_already_visited.insert(this_node_info.remote_endpoint);

    peer_probe probe;
    try
    {
      probe.start(this_node_info.remote_endpoint, 
                  my_node_id,
                  chain_db->chain_id());
      probe.wait();

      this_node_info.node_id = probe._node_id;

      connections_by_node_id[this_node_info.node_id] = probe._peers;
      if (address_info_by_node_id.find(probe._node_id) == address_info_by_node_id.end())
        address_info_by_node_id[probe._node_id] = this_node_info;

      for (const bts::net::address_info& info : probe._peers)
      {
        if (nodes_already_visited.find(info.remote_endpoint) == nodes_already_visited.end() && 
            info.firewalled == bts::net::firewalled_state::not_firewalled &&
            nodes_to_visit_set.find(info.remote_endpoint) == nodes_to_visit_set.end())
        {
          nodes_to_visit.push(info.remote_endpoint);
          nodes_to_visit_set.insert(info.remote_endpoint);
        }
        if (address_info_by_node_id.find(info.node_id) == address_info_by_node_id.end())
          address_info_by_node_id[info.node_id] = info;
      }
    }
    catch (const fc::exception&)
    {
    }
    std::cout << "Traversed " << nodes_already_visited.size() << " of " << (nodes_already_visited.size() + nodes_to_visit.size()) << " known nodes\n";
  }

  bts::net::node_id_t seed_node_id;
  std::set<bts::net::node_id_t> non_firewalled_nodes_set;
  for (const auto& address_info_for_node : address_info_by_node_id)
  {
    if (address_info_for_node.second.remote_endpoint == seed_node1)
      seed_node_id = address_info_for_node.first;
    if (address_info_for_node.second.firewalled == bts::net::firewalled_state::not_firewalled)
      non_firewalled_nodes_set.insert(address_info_for_node.first);
  }
  std::set<bts::net::node_id_t> seed_node_connections;
  for (const bts::net::address_info& info : connections_by_node_id[seed_node_id])
    seed_node_connections.insert(info.node_id);
  std::set<bts::net::node_id_t> seed_node_missing_connections;
  std::set_difference(non_firewalled_nodes_set.begin(), non_firewalled_nodes_set.end(),
                      seed_node_connections.begin(), seed_node_connections.end(),
                      std::inserter(seed_node_missing_connections, seed_node_missing_connections.end()));
  seed_node_missing_connections.erase(seed_node_id);

  std::ofstream dot_stream((data_dir / "network_graph.dot").string().c_str());
  std::map<bts::net::node_id_t, fc::ip::endpoint> all_known_nodes;

  dot_stream << "graph G {\n";
  dot_stream << "  // Total " << address_info_by_node_id.size() << " nodes, firewalled: " << (address_info_by_node_id.size() - non_firewalled_nodes_set.size())
                              << ", non-firewalled: " << non_firewalled_nodes_set.size() << "\n";
  dot_stream << "  // Seed node is " << (std::string)address_info_by_node_id[seed_node_id].remote_endpoint << " id: " << fc::variant(seed_node_id).as_string() << "\n";
  dot_stream << "  // Seed node is connected to " << connections_by_node_id[seed_node_id].size() << " nodes\n";
  dot_stream << "  // Seed node is missing connections to " << seed_node_missing_connections.size() << " non-firewalled nodes:\n";
  for (const bts::net::node_id_t& id : seed_node_missing_connections)
    dot_stream << "  //           " << (std::string)address_info_by_node_id[id].remote_endpoint << "\n";
  
  dot_stream << "  layout=\"circo\";\n";
  //for (const auto& node_and_connections : connections_by_node_id)
  //  all_known_nodes[node_and_connections.first] = address_info_by_node_id[node_and_connections.first].remote_endpoint;

  for (const auto& address_info_for_node : address_info_by_node_id)
  {
    dot_stream << "  \"" << fc::variant(address_info_for_node.first).as_string() << "\"[label=\"" << (std::string)address_info_for_node.second.remote_endpoint << "\"";
    if (address_info_for_node.second.firewalled != bts::net::firewalled_state::not_firewalled)
      dot_stream << ",shape=rectangle";
    dot_stream << "];\n";
  }
  for (auto& node_and_connections : connections_by_node_id)
    for (const bts::net::address_info& this_connection : node_and_connections.second)
      dot_stream << "  \"" << fc::variant(node_and_connections.first).as_string() << "\" -- \"" << fc::variant(this_connection.node_id).as_string() << "\";\n";

  dot_stream << "}\n";

#if 0
  for (auto& node_and_connections : connections_by_node_id)
  {
    out << "  " << (std::string)node_and_connections.first.node_id.data << "[label=\"" << (std::string)node_and_connections.first.remote_endpoint << "\"];\n";
    //node_and_connections.first.node_id
  }
#endif

  return 0;
}