P2P網絡數據處理流程

P2P網絡數據處理流程

監聽(ListenLoop)+撥號(Dial) –> 創建鏈接(SetupConn) –> Enc 握手(doEncHandshake) –> 協議握手(doProtoHandshake) –> 添加Peer Addpeer –> Run Peer網絡

1. Enc握手 doEncHandshake

監聽時接收到Enc握手:receiverEncHandshakeapp

撥號時發起初始End握手:initiatorEncHandshake函數

連接的發起者被稱爲initiator(主動撥號),連接的被動接受者被成爲receiver(被動監聽)。 這兩種模式下處理的流程是不一樣的,完成握手後, 生成了一個sec能夠理解爲拿到了對稱加密的密鑰。 而後建立了一個newRLPXFrameRW幀讀寫器,完成加密信道的建立過程。oop

initiatorEncHandshake 和receiverEncHandshake有些像,但邏輯處理是相反的過程。編碼

makeAuthMsg

makeAuthMsg這個方法建立了handshake message。 首先對端的公鑰能夠經過對端的ID來獲取。對端的公鑰對於發起者來講是知道的;對於接收者來講是不知道的。加密

  • 根據對端的ID計算出對端公鑰remotePub
  • 生成一個隨機的初始值initNonce
  • 生成一個隨機的私鑰
  • 使用本身的私鑰和對方的公鑰生成的一個共享祕密
  • 用共享祕密來加密這個initNonce
  • 這裏把發起者的公鑰告知對方

這一步,主要是構建authMsgV4結構體。spa

sealEIP8

sealEIP8對msg進行rlp的編碼,填充一下數據,而後使用對方的公鑰把數據進行加密。3d

readHandshakeMsg

readHandshakeMsg有兩個地方調用: 一個是在initiatorEncHandshake,另一個就是在receiverEncHandshake。 這個方法比較簡單, 首先用一種格式嘗試解碼,若是不行就換另一種。基本上就是使用本身的私鑰進行解碼而後調用rlp解碼成結構體。 結構體的描述就是authRespV4,裏面最重要的就是對端的隨機公鑰。 雙方經過本身的私鑰和對端的隨機公鑰能夠獲得同樣的共享祕密。 而這個共享祕密是第三方拿不到的。code

secrets

secrets函數是在handshake完成以後調用。它經過本身的隨機私鑰和對端的公鑰來生成一個共享祕密,這個共享祕密是瞬時的(只在當前這個連接中存在)。orm

這個函數計算出IngressMAC和EgressMAC用於rlpxFrameRW中ReadMsg,WriteMsg數據的接收發送。

數據幀結構

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 
normal = not chunked   chunked-0 = First frame of a multi-frame packet   chunked-n = Subsequent frames for multi-frame packet   || is concatenate   ^ is xor    Single-frame packet:  header || header-mac || frame || frame-mac    Multi-frame packet:  header || header-mac || frame-0 ||  [ header || header-mac || frame-n || ... || ]  header || header-mac || frame-last || frame-mac    header: frame-size || header-data || padding  frame-size: 3-byte integer size of frame, big endian encoded (excludes padding)  header-data:   normal: rlp.list(protocol-type[, context-id])   chunked-0: rlp.list(protocol-type, context-id, total-packet-size)   chunked-n: rlp.list(protocol-type, context-id)   values:   protocol-type: < 2**16   context-id: < 2**16 (optional for normal frames)   total-packet-size: < 2**32  padding: zero-fill to 16-byte boundary    header-mac: right128 of egress-mac.update(aes(mac-secret,egress-mac) ^ header-ciphertext).digest    frame:   normal: rlp(packet-type) [|| rlp(packet-data)] || padding   chunked-0: rlp(packet-type) || rlp(packet-data...)   chunked-n: rlp(...packet-data) || padding  padding: zero-fill to 16-byte boundary (only necessary for last frame)    frame-mac: right128 of egress-mac.update(aes(mac-secret,egress-mac) ^ right128(egress-mac.update(frame-ciphertext).digest))    egress-mac: h256, continuously updated with egress-bytes*  ingress-mac: h256, continuously updated with ingress-bytes*

2. 協議握手doProtoHandshake

這個方法比較簡單,加密信道已經建立完畢。 咱們看到這裏只是約定了是否使用Snappy加密而後就退出了。

在這個函數,發送給對方 handshakeMsg = 0x00,在readProtocolHandshake中讀取接收對方發過來的handshakeMsg。

3. RLPX 數據分幀

在完成Encode握手以後,調用newRLPXFrameRW方法建立rlpxFrameRW對象,這的對象提供ReadMsg和WriteMsg方法

ReadMsg

)

1讀取幀頭header

2 驗證幀頭MAC

3 獲取幀體Frame大小

4 讀取幀體數據

5 驗證幀體MAC信息

6 解密幀體內容(NewCTR à XORKeyStream)

7 解碼幀體(RLP Decode)

8 解析幀體結構(msg.Size & msg.Payload)

9 snappy解碼

WriteMsg

1 RLP編碼msg.Code

2 若是snappy,就對讀取payload並進行snappy編碼

3 寫幀頭header (32字節)

4 寫幀頭MAC

5 寫幀體信息(ptype+payload+padding)

6 寫幀體MAC

4. runPeer

newPeerHook,創建peer的鉤子函數

廣播PeerEventTypeAdd事件

運行protocol

廣播PeerEventTypeDrop事件

刪除peer

run protocol

1 啓動協程readLoop,讀取消息並根據msg.Code處理消息:

pingMsg->pongMsg

discMsg->RLP解碼msg.Payload返回reason

其餘協議消息處理,根據msg.Code的取值範圍,把msg分給註冊的協議進行處理。

2 啓動協程pingLoop

根據pingInterval(15秒)定時發送pingMsg消息

3 啓動協議

startProtocols主要功能是啓動協程運行註冊協議的run函數proto.Run(p, rw),這個rw參數類型是protoRW,它實現的ReadMsg和WriteMsg增長msg.Code取值範圍的處理。不一樣的protocol有不一樣的code取值範圍,根據offset和Length肯定。

 

原文連接:http://wangxiaoming.com/blog/2018/06/28/HPB-48-ETH-P2P-Net/

相關文章
相關標籤/搜索