P2P網絡數據處理流程


P2P網絡數據處理流程

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

1. Enc握手 doEncHandshake

監聽時接收到Enc握手:receiverEncHandshake

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

鏈接的發起者被稱為initiator(主動撥號),鏈接的被動接受者被成為receiver(被動監聽)。 這兩種模式下處理的流程是不同的,完成握手后, 生成了一個sec可以理解為拿到了對稱加密的密鑰。 然后創建了一個newRLPXFrameRW幀讀寫器,完成加密信道的創建過程。

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

makeAuthMsg

makeAuthMsg這個方法創建了handshake message。 首先對端的公鑰可以通過對端的ID來獲取。對端的公鑰對於發起者來說是知道的;對於接收者來說是不知道的。

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

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

sealEIP8

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

readHandshakeMsg

readHandshakeMsg有兩個地方調用: 一個是在initiatorEncHandshake,另外一個就是在receiverEncHandshake。 這個方法比較簡單, 首先用一種格式嘗試解碼,如果不行就換另外一種。基本上就是使用自己的私鑰進行解碼然后調用rlp解碼成結構體。 結構體的描述就是authRespV4,里面最重要的就是對端的隨機公鑰。 雙方通過自己的私鑰和對端的隨機公鑰可以得到一樣的共享秘密。 而這個共享秘密是第三方拿不到的。

secrets

secrets函數是在handshake完成之后調用。它通過自己的隨機私鑰和對端的公鑰來生成一個共享秘密,這個共享秘密是瞬時的(只在當前這個鏈接中存在)。

這個函數計算出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/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM