以太坊P2P 流程 整体框架

以太坊底层P2P代码细节很多,深入进去,会丢失整体框架,所以按照自己的习惯,先明白框架结构,了然于胸,然后再深入细节,所以这一节就先用白话总结下整体的流程。

入口:

1. P2P层分为两个部分,一层是基于UDP的节点Node发现,二是基于TCP的节点Peer的消息交互。注意这里的两个英文单词,Node,是网络上的节点,Peer是已经连接的节点

2. 两个过程依次涉及两个大类NodeTable 和 Host,其中NodeTable又是Host的成员变量, Host是WebThreeDirect的成员变量,

WebThreeDirect又继承了接口类NetworkFace

class NetworkFace
{
public:
    virtual ~NetworkFace() = default;

    /// Get information concerning this node.
    virtual p2p::NodeInfo nodeInfo() const = 0;

    /// Get information on the current peer set.
    virtual std::vector<p2p::PeerSessionInfo> peers() = 0;

    /// Same as peers().size(), but more efficient.
    virtual size_t peerCount() const = 0;

    /// Generalised peer addition.
    virtual void addPeer(p2p::NodeSpec const& _node, p2p::PeerType _t) = 0;

    /// Add node to connect to.
    virtual void addNode(p2p::NodeID const& _node, bi::tcp::endpoint const& _hostEndpoint) = 0;
    
    /// Require connection to peer.
    virtual void requirePeer(p2p::NodeID const& _node, bi::tcp::endpoint const& _endpoint) = 0;
    
    /// Save peers
    virtual dev::bytes saveNetwork() = 0;

    /// Sets the ideal number of peers.
    virtual void setIdealPeerCount(size_t _n) = 0;

    /// Get network id
    virtual u256 networkId() const = 0;

    /// Start the network subsystem.
    virtual void startNetwork() = 0;

    /// Stop the network subsystem.
    virtual void stopNetwork() = 0;

    /// Is network working? there may not be any peers yet.
    virtual bool isNetworkStarted() const = 0;

    /// Get enode string.
    virtual std::string enode() const = 0;
};

NetworkFace 提供接口,可以看出主要有3大块,node、peer、network

看下WebThreeDirect的定义, 继承NetworkFace后,增加了主要的成员变量,主要的是p2p::Host m_net;  实现虚函数的过程也是封装了Host的实际实现函数,例如 addPeer --> m_net.addPeer(_s, _t);

/**
 * @brief Main API hub for interfacing with Web 3 components. This doesn't do any local multiplexing, so you can only have one
 * running on any given machine for the provided DB path.
 *
 * Keeps a libp2p Host going (administering the work thread with m_workNet).
 *
 * Encapsulates a bunch of P2P protocols (interfaces), each using the same underlying libp2p Host.
 *
 * Provides a baseline for the multiplexed multi-protocol session class, WebThree.
 */
class WebThreeDirect: public NetworkFace
{
    private:
    std::string m_clientVersion;                    ///< Our end-application client's name/version.

    std::unique_ptr<eth::Client> m_ethereum;        ///< Client for Ethereum ("eth") protocol.

    p2p::Host m_net;                                ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
}

启动:

在aleth\main.cpp的main函数中,建立WebThreeDirect对象

    dev::WebThreeDirect web3(WebThreeDirect::composeClientVersion("aleth"), db::databasePath(),
        snapshotPath, chainParams, withExisting, netPrefs, &nodesState, testingMode);

开始设置Host的环境,启动:

   // 设置peer的个数,如果是主动连接的有11个,如果是被动连接,可以有11* 7个
   web3.setIdealPeerCount(peers);  // 11
   web3.setPeerStretch(peerStretch); // 7

    // 还是启动host,后续再具体分析
    if (bootstrap || !remoteHost.empty() || enableDiscovery || listenSet || !preferredNodes.empty())
    {
        web3.startNetwork(); // --- host->start()
        cout << "Node ID: " << web3.enode() << "\n";
    }

    // 为发现node 增加源,也就是从这些固定节点开始进行节点发现
    if (bootstrap && privateChain.empty())
    for (auto const& i: Host::pocHosts())
         web3.requirePeer(i.first, i.second);
    if (!remoteHost.empty())
         web3.addNode(p2p::NodeID(), remoteHost + ":" + toString(remotePort));

host->start() 里面调用startedWorking(), 再这里面完成了置位启动标记位,设置tcp的监听,创建nodeTabel(nodeTable 再构造中开启upd连接,发现节点)

void Host::startedWorking()
{
    asserts(!m_timer);

    {   ......
        m_run = true;
    }

    ......

    // try to open acceptor (todo: ipv6)
    int port = Network::tcp4Listen(m_tcp4Acceptor, m_netConfig);
    if (port > 0)
    {
        m_listenPort = port;
        determinePublic();
        runAcceptor();  // 这里面开始异步接受节点信息,进行握手,建立连接
    }
    
    ......

    auto nodeTable = make_shared<NodeTable>(
        m_ioService,
        m_alias,
        NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort()),
        m_netConfig.discovery
    ); // 里面建立UDP监听,开始发现节点
    
    nodeTable->setEventHandler(new HostNodeTableHandler(*this));
    DEV_GUARDED(x_nodeTable)
        m_nodeTable = nodeTable;
    restoreNetwork(&m_restoreNetwork);

    LOG(m_logger) << "p2p.started id: " << id();

    run(boost::system::error_code());
}

Host::pocHosts() 里面写死了6个(主网)Node的信息(NodeID, IP, Port)。再上线的nodeTable发现节点时,开始为空,先添加固定的节点,然后基于这些固定节点节点发现

NodeTable::NodeTable(
    ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled)
  : m_hostNodeID(_alias.pub()),
    m_hostNodeEndpoint(_endpoint),
    m_secret(_alias.secret()),
    m_socket(make_shared<NodeSocket>(
        _io, static_cast<UDPSocketEvents&>(*this), (bi::udp::endpoint)m_hostNodeEndpoint)),
    m_timers(_io)
{
    ......
    try
    {
        m_socket->connect(); //UDP 配置
        doDiscovery(); // 节点发现
        doHandleTimeouts();
    }
    ......
}

节点发现过程参见  https://blog.csdn.net/laorenmen/article/details/85014195  以太坊P2P流程 1

握手流程,参见 https://blog.csdn.net/laorenmen/article/details/85043601       以太坊P2P流程2

                          https://blog.csdn.net/laorenmen/article/details/85059348       以太坊P2P流程3

上面的文章分别介绍了Node发现和Peer握手流程,最后在握手成功(收到hello报文后)进入 host-> startPeerSession参见下一篇学习笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值