監聽(ListenLoop)+撥號(Dial) –> 創建鏈接(SetupConn) –> Enc 握手(doEncHandshake) –> 協議握手(doProtoHandshake) –> 添加Peer Addpeer –> Run Peer網絡
監聽時接收到Enc握手:receiverEncHandshakeapp
撥號時發起初始End握手:initiatorEncHandshake函數
連接的發起者被稱爲initiator(主動撥號),連接的被動接受者被成爲receiver(被動監聽)。 這兩種模式下處理的流程是不一樣的,完成握手後, 生成了一個sec能夠理解爲拿到了對稱加密的密鑰。 而後建立了一個newRLPXFrameRW幀讀寫器,完成加密信道的建立過程。oop
initiatorEncHandshake 和receiverEncHandshake有些像,但邏輯處理是相反的過程。編碼
makeAuthMsg這個方法建立了handshake message。 首先對端的公鑰能夠經過對端的ID來獲取。對端的公鑰對於發起者來講是知道的;對於接收者來講是不知道的。加密
這一步,主要是構建authMsgV4結構體。spa
sealEIP8對msg進行rlp的編碼,填充一下數據,而後使用對方的公鑰把數據進行加密。3d
readHandshakeMsg有兩個地方調用: 一個是在initiatorEncHandshake,另一個就是在receiverEncHandshake。 這個方法比較簡單, 首先用一種格式嘗試解碼,若是不行就換另一種。基本上就是使用本身的私鑰進行解碼而後調用rlp解碼成結構體。 結構體的描述就是authRespV4,裏面最重要的就是對端的隨機公鑰。 雙方經過本身的私鑰和對端的隨機公鑰能夠獲得同樣的共享祕密。 而這個共享祕密是第三方拿不到的。code
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* |
這個方法比較簡單,加密信道已經建立完畢。 咱們看到這裏只是約定了是否使用Snappy加密而後就退出了。
在這個函數,發送給對方 handshakeMsg = 0x00,在readProtocolHandshake中讀取接收對方發過來的handshakeMsg。
在完成Encode握手以後,調用newRLPXFrameRW方法建立rlpxFrameRW對象,這的對象提供ReadMsg和WriteMsg方法
)
1讀取幀頭header
2 驗證幀頭MAC
3 獲取幀體Frame大小
4 讀取幀體數據
5 驗證幀體MAC信息
6 解密幀體內容(NewCTR à XORKeyStream)
7 解碼幀體(RLP Decode)
8 解析幀體結構(msg.Size & msg.Payload)
9 snappy解碼
1 RLP編碼msg.Code
2 若是snappy,就對讀取payload並進行snappy編碼
3 寫幀頭header (32字節)
4 寫幀頭MAC
5 寫幀體信息(ptype+payload+padding)
6 寫幀體MAC
newPeerHook,創建peer的鉤子函數
廣播PeerEventTypeAdd事件
運行protocol
廣播PeerEventTypeDrop事件
刪除peer
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/