簡(jiǎn)介
在以太坊上P2P網(wǎng)絡(luò)上使用了多種數(shù)據(jù)要交互桂塞,這就會(huì)涉及的很多種協(xié)議凹蜂,所以以太坊使用了RPLx協(xié)議,它是一個(gè)加密的點(diǎn)對(duì)點(diǎn)的協(xié)議套件阁危,它為在P2P網(wǎng)絡(luò)上交互的應(yīng)用提供了一套統(tǒng)一的傳輸接口玛痊,它設(shè)計(jì)的初衷便是滿足去中心化應(yīng)用。
結(jié)構(gòu)圖
概述
RLPx協(xié)議建立在tcp以及udp之上狂打,它包含四個(gè)組件擂煞,分別為Node Disvovery、Handshake趴乡、Framing对省、Flow Control蝗拿,下面分別就其實(shí)現(xiàn)進(jìn)行分析
Node Disvovery (節(jié)點(diǎn)發(fā)現(xiàn)):
它在上篇文章節(jié)點(diǎn)發(fā)現(xiàn)有過(guò)分析,它主要是基于UDP實(shí)現(xiàn)的蒿涎,這里就不再贅述哀托。Encrypted Handshake:
連接在建立之初,會(huì)有一個(gè)連接的握手(區(qū)分于tcp的握手)劳秋,它的基本過(guò)程分為兩個(gè)階段:
- 第一個(gè)階段為密鑰交換仓手,它使用ECIES加密臨時(shí)密鑰傳給peer
- 第二階段為認(rèn)證和協(xié)議協(xié)商,協(xié)商的協(xié)議為是否支持傳過(guò)來(lái)的協(xié)議它包含(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();
...省略
}
Fraaming:
協(xié)議幀的作用就是在RLPx協(xié)議之上能夠支持多種協(xié)議的傳輸Flow control:
RLPx協(xié)議設(shè)置了一個(gè)8K的窗口來(lái)控制流量。
實(shí)現(xiàn)
在握手通過(guò)之后补履,握手處理器被移除辛慰,后續(xù)增加了p2p的處理器,通過(guò)hellomessage的Capability區(qū)分出協(xié)議類型干像,根據(jù)協(xié)議類型激活不同的協(xié)議:
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方法中完成了不同協(xié)議的激活:
public void setHandshake(HelloMessage msg, ChannelHandlerContext ctx) {
....省略
this.handshakeHelloMessage = msg;
List<Capability> 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);
}
}
}