github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/protocol.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:39</date> 10 //</624450095793836032> 11 12 13 //包les实现轻以太坊子协议。 14 package les 15 16 import ( 17 "crypto/ecdsa" 18 "errors" 19 "fmt" 20 "io" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core" 25 "github.com/ethereum/go-ethereum/core/rawdb" 26 "github.com/ethereum/go-ethereum/crypto" 27 "github.com/ethereum/go-ethereum/p2p/enode" 28 "github.com/ethereum/go-ethereum/rlp" 29 ) 30 31 //用于匹配协议版本和消息的常量 32 const ( 33 lpv1 = 1 34 lpv2 = 2 35 ) 36 37 //支持的LES协议版本(第一个是主协议) 38 var ( 39 ClientProtocolVersions = []uint{lpv2, lpv1} 40 ServerProtocolVersions = []uint{lpv2, lpv1} 41 AdvertiseProtocolVersions = []uint{lpv2} //客户端正在搜索列表中的第一个公告协议 42 ) 43 44 //对应于不同协议版本的已实现消息数。 45 var ProtocolLengths = map[uint]uint64{lpv1: 15, lpv2: 22} 46 47 const ( 48 NetworkId = 1 49 ProtocolMaxMsgSize = 10 * 1024 * 1024 //协议消息大小的最大上限 50 ) 51 52 //LES协议消息代码 53 const ( 54 //属于lpv1的协议消息 55 StatusMsg = 0x00 56 AnnounceMsg = 0x01 57 GetBlockHeadersMsg = 0x02 58 BlockHeadersMsg = 0x03 59 GetBlockBodiesMsg = 0x04 60 BlockBodiesMsg = 0x05 61 GetReceiptsMsg = 0x06 62 ReceiptsMsg = 0x07 63 GetProofsV1Msg = 0x08 64 ProofsV1Msg = 0x09 65 GetCodeMsg = 0x0a 66 CodeMsg = 0x0b 67 SendTxMsg = 0x0c 68 GetHeaderProofsMsg = 0x0d 69 HeaderProofsMsg = 0x0e 70 //属于lpv2的协议消息 71 GetProofsV2Msg = 0x0f 72 ProofsV2Msg = 0x10 73 GetHelperTrieProofsMsg = 0x11 74 HelperTrieProofsMsg = 0x12 75 SendTxV2Msg = 0x13 76 GetTxStatusMsg = 0x14 77 TxStatusMsg = 0x15 78 ) 79 80 type errCode int 81 82 const ( 83 ErrMsgTooLarge = iota 84 ErrDecode 85 ErrInvalidMsgCode 86 ErrProtocolVersionMismatch 87 ErrNetworkIdMismatch 88 ErrGenesisBlockMismatch 89 ErrNoStatusMsg 90 ErrExtraStatusMsg 91 ErrSuspendedPeer 92 ErrUselessPeer 93 ErrRequestRejected 94 ErrUnexpectedResponse 95 ErrInvalidResponse 96 ErrTooManyTimeouts 97 ErrMissingKey 98 ) 99 100 func (e errCode) String() string { 101 return errorToString[int(e)] 102 } 103 104 //一旦旧代码用完,XXX就会更改 105 var errorToString = map[int]string{ 106 ErrMsgTooLarge: "Message too long", 107 ErrDecode: "Invalid message", 108 ErrInvalidMsgCode: "Invalid message code", 109 ErrProtocolVersionMismatch: "Protocol version mismatch", 110 ErrNetworkIdMismatch: "NetworkId mismatch", 111 ErrGenesisBlockMismatch: "Genesis block mismatch", 112 ErrNoStatusMsg: "No status message", 113 ErrExtraStatusMsg: "Extra status message", 114 ErrSuspendedPeer: "Suspended peer", 115 ErrRequestRejected: "Request rejected", 116 ErrUnexpectedResponse: "Unexpected response", 117 ErrInvalidResponse: "Invalid response", 118 ErrTooManyTimeouts: "Too many request timeouts", 119 ErrMissingKey: "Key missing from list", 120 } 121 122 type announceBlock struct { 123 Hash common.Hash //正在公布的一个特定块的哈希 124 Number uint64 //公布的一个特定区块的编号 125 Td *big.Int //宣布一个特定区块的总难度 126 } 127 128 //公告数据是块公告的网络包。 129 type announceData struct { 130 Hash common.Hash //正在公布的一个特定块的哈希 131 Number uint64 //公布的一个特定区块的编号 132 Td *big.Int //宣布一个特定区块的总难度 133 ReorgDepth uint64 134 Update keyValueList 135 } 136 137 //签名通过给定的私钥向块公告添加签名 138 func (a *announceData) sign(privKey *ecdsa.PrivateKey) { 139 rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td}) 140 sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey) 141 a.Update = a.Update.add("sign", sig) 142 } 143 144 //checksignature验证块通知是否具有给定pubkey的有效签名 145 func (a *announceData) checkSignature(id enode.ID) error { 146 var sig []byte 147 if err := a.Update.decode().get("sign", &sig); err != nil { 148 return err 149 } 150 rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td}) 151 recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig) 152 if err != nil { 153 return err 154 } 155 if id == enode.PubkeyToIDV4(recPubkey) { 156 return nil 157 } 158 return errors.New("wrong signature") 159 } 160 161 type blockInfo struct { 162 Hash common.Hash //正在公布的一个特定块的哈希 163 Number uint64 //公布的一个特定区块的编号 164 Td *big.Int //宣布一个特定区块的总难度 165 } 166 167 //GetBlockHeadersData表示块头查询。 168 type getBlockHeadersData struct { 169 Origin hashOrNumber //从中检索邮件头的块 170 Amount uint64 //要检索的最大头数 171 Skip uint64 //要在连续标题之间跳过的块 172 Reverse bool //查询方向(假=上升到最新,真=下降到创世纪) 173 } 174 175 //hashornumber是用于指定源块的组合字段。 176 type hashOrNumber struct { 177 Hash common.Hash //要从中检索头的块哈希(不包括数字) 178 Number uint64 //要从中检索头的块哈希(不包括哈希) 179 } 180 181 //encoderlp是一个专门的编码器,用于hashornumber只对 182 //两个包含联合字段。 183 func (hn *hashOrNumber) EncodeRLP(w io.Writer) error { 184 if hn.Hash == (common.Hash{}) { 185 return rlp.Encode(w, hn.Number) 186 } 187 if hn.Number != 0 { 188 return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number) 189 } 190 return rlp.Encode(w, hn.Hash) 191 } 192 193 //decoderlp是一种特殊的译码器,用于hashornumber对内容进行译码。 194 //分块散列或分块编号。 195 func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error { 196 _, size, _ := s.Kind() 197 origin, err := s.Raw() 198 if err == nil { 199 switch { 200 case size == 32: 201 err = rlp.DecodeBytes(origin, &hn.Hash) 202 case size <= 8: 203 err = rlp.DecodeBytes(origin, &hn.Number) 204 default: 205 err = fmt.Errorf("invalid input size %d for origin", size) 206 } 207 } 208 return err 209 } 210 211 //codedata是用于节点数据检索的网络响应包。 212 type CodeData []struct { 213 Value []byte 214 } 215 216 type proofsData [][]rlp.RawValue 217 218 type txStatus struct { 219 Status core.TxStatus 220 Lookup *rawdb.TxLookupEntry `rlp:"nil"` 221 Error string 222 } 223