以太坊源码分析(五 协议栈)

简介

在以太坊上P2P网络上使用了多种数据要交互,这就会涉及的很多种协议,所以以太坊使用了RPLx协议,它是一个加密的点对点的协议套件,它为在P2P网络上交互的应用提供了一套统一的传输接口,它设计的初衷便是满足去中心化应用。

结构图

image.png

概述

RLPx协议建立在tcp以及udp之上,它包含四个组件,分别为Node Disvovery、Handshake、Framing、Flow Control,下面分别就其实现进行分析

  1. Node Disvovery (节点发现):
    它在上篇文章节点发现有过分析,它主要是基于UDP实现的,这里就不再赘述。

  2. Encrypted Handshake:
    连接在建立之初,会有一个连接的握手(区分于tcp的握手),它的基本过程分为两个阶段:

  • 第一个阶段为密钥交换,它使用ECIES加密临时密钥传给peer
  • 第二阶段为认证和协议协商,协商的协议为是否支持传过来的协议它包含(shh、eth、bzz)
    部分代码如下:
 public void initiate(ChannelHandlerContext ctx) throws Exception {

        loggerNet.debug("RLPX protocol activated");

        nodeId = myKey.getNodeId();

        handshake = new EncryptionHandshake(ECKey.fromNodeId(this.remoteId).getPubKeyPoint());

        Object msg;
        if (config.eip8()) {
            AuthInitiateMessageV4 initiateMessage = handshake.createAuthInitiateV4(myKey);
            initiatePacket = handshake.encryptAuthInitiateV4(initiateMessage);
            msg = initiateMessage;
        } else {
            AuthInitiateMessage initiateMessage = handshake.createAuthInitiate(null, myKey);
            initiatePacket = handshake.encryptAuthMessage(initiateMessage);
            msg = initiateMessage;
        }

        final ByteBuf byteBufMsg = ctx.alloc().buffer(initiatePacket.length);
        byteBufMsg.writeBytes(initiatePacket);
        ctx.writeAndFlush(byteBufMsg).sync();
...省略
    }
  1. Fraaming:
    协议帧的作用就是在RLPx协议之上能够支持多种协议的传输

  2. Flow control:
    RLPx协议设置了一个8K的窗口来控制流量。

实现

在握手通过之后,握手处理器被移除,后续增加了p2p的处理器,通过hellomessage的Capability区分出协议类型,根据协议类型激活不同的协议:

public void publicRLPxHandshakeFinished(ChannelHandlerContext ctx, FrameCodec frameCodec,
                                            HelloMessage helloRemote) throws IOException, InterruptedException {

        logger.debug("publicRLPxHandshakeFinished with " + ctx.channel().remoteAddress());

        messageCodec.setSupportChunkedFrames(false);

        FrameCodecHandler frameCodecHandler = new FrameCodecHandler(frameCodec, this);
        ctx.pipeline().addLast("medianFrameCodec", frameCodecHandler);
        ctx.pipeline().addLast("messageCodec", messageCodec);
        ctx.pipeline().addLast(Capability.P2P, p2pHandler);

        p2pHandler.setChannel(this);
        p2pHandler.setHandshake(helloRemote, ctx);

        getNodeStatistics().rlpxHandshake.add();
    }

在setHandshake方法中完成了不同协议的激活:

public void setHandshake(HelloMessage msg, ChannelHandlerContext ctx) {
....省略
        this.handshakeHelloMessage = msg;

        List capInCommon = getSupportedCapabilities(msg);
        channel.initMessageCodes(capInCommon);
        for (Capability capability : capInCommon) {
            if (capability.getName().equals(Capability.ETH)) {

                // Activate EthHandler for this peer
                channel.activateEth(ctx, fromCode(capability.getVersion()));
            } else if
               (capability.getName().equals(Capability.SHH) &&
                capability.getVersion() == ShhHandler.VERSION) {

                // Activate ShhHandler for this peer
                channel.activateShh(ctx);
            } else if
               (capability.getName().equals(Capability.BZZ) &&
                capability.getVersion() == BzzHandler.VERSION) {

                // Activate ShhHandler for this peer
                channel.activateBzz(ctx);
            }
        }
    }

你可能感兴趣的:(以太坊源码分析(五 协议栈))