github.com/edxfund/validator@v1.8.16-0.20181020093046-c1def72855da/les/protocol.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package les implements the Light Ethereum Subprotocol. 18 package les 19 20 import ( 21 "bytes" 22 "crypto/ecdsa" 23 "crypto/elliptic" 24 "errors" 25 "fmt" 26 "io" 27 "math/big" 28 29 "github.com/EDXFund/Validator/common" 30 "github.com/EDXFund/Validator/core" 31 "github.com/EDXFund/Validator/core/rawdb" 32 "github.com/EDXFund/Validator/crypto" 33 "github.com/EDXFund/Validator/crypto/secp256k1" 34 "github.com/EDXFund/Validator/rlp" 35 ) 36 37 // Constants to match up protocol versions and messages 38 const ( 39 lpv1 = 1 40 lpv2 = 2 41 ) 42 43 // Supported versions of the les protocol (first is primary) 44 var ( 45 ClientProtocolVersions = []uint{lpv2, lpv1} 46 ServerProtocolVersions = []uint{lpv2, lpv1} 47 AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list 48 ) 49 50 // Number of implemented message corresponding to different protocol versions. 51 var ProtocolLengths = map[uint]uint64{lpv1: 15, lpv2: 22} 52 53 const ( 54 NetworkId = 1 55 ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message 56 ) 57 58 // les protocol message codes 59 const ( 60 // Protocol messages belonging to LPV1 61 StatusMsg = 0x00 62 AnnounceMsg = 0x01 63 GetBlockHeadersMsg = 0x02 64 BlockHeadersMsg = 0x03 65 GetBlockBodiesMsg = 0x04 66 BlockBodiesMsg = 0x05 67 GetReceiptsMsg = 0x06 68 ReceiptsMsg = 0x07 69 GetProofsV1Msg = 0x08 70 ProofsV1Msg = 0x09 71 GetCodeMsg = 0x0a 72 CodeMsg = 0x0b 73 SendTxMsg = 0x0c 74 GetHeaderProofsMsg = 0x0d 75 HeaderProofsMsg = 0x0e 76 // Protocol messages belonging to LPV2 77 GetProofsV2Msg = 0x0f 78 ProofsV2Msg = 0x10 79 GetHelperTrieProofsMsg = 0x11 80 HelperTrieProofsMsg = 0x12 81 SendTxV2Msg = 0x13 82 GetTxStatusMsg = 0x14 83 TxStatusMsg = 0x15 84 ) 85 86 type errCode int 87 88 const ( 89 ErrMsgTooLarge = iota 90 ErrDecode 91 ErrInvalidMsgCode 92 ErrProtocolVersionMismatch 93 ErrNetworkIdMismatch 94 ErrGenesisBlockMismatch 95 ErrNoStatusMsg 96 ErrExtraStatusMsg 97 ErrSuspendedPeer 98 ErrUselessPeer 99 ErrRequestRejected 100 ErrUnexpectedResponse 101 ErrInvalidResponse 102 ErrTooManyTimeouts 103 ErrMissingKey 104 ErrNotImplemented 105 ) 106 107 func (e errCode) String() string { 108 return errorToString[int(e)] 109 } 110 111 // XXX change once legacy code is out 112 var errorToString = map[int]string{ 113 ErrMsgTooLarge: "Message too long", 114 ErrDecode: "Invalid message", 115 ErrInvalidMsgCode: "Invalid message code", 116 ErrProtocolVersionMismatch: "Protocol version mismatch", 117 ErrNetworkIdMismatch: "NetworkId mismatch", 118 ErrGenesisBlockMismatch: "Genesis block mismatch", 119 ErrNoStatusMsg: "No status message", 120 ErrExtraStatusMsg: "Extra status message", 121 ErrSuspendedPeer: "Suspended peer", 122 ErrRequestRejected: "Request rejected", 123 ErrUnexpectedResponse: "Unexpected response", 124 ErrInvalidResponse: "Invalid response", 125 ErrTooManyTimeouts: "Too many request timeouts", 126 ErrMissingKey: "Key missing from list", 127 } 128 129 type announceBlock struct { 130 Hash common.Hash // Hash of one particular block being announced 131 Number uint64 // Number of one particular block being announced 132 Td *big.Int // Total difficulty of one particular block being announced 133 } 134 135 // announceData is the network packet for the block announcements. 136 type announceData struct { 137 Hash common.Hash // Hash of one particular block being announced 138 Number uint64 // Number of one particular block being announced 139 Td *big.Int // Total difficulty of one particular block being announced 140 ReorgDepth uint64 141 Update keyValueList 142 } 143 144 // sign adds a signature to the block announcement by the given privKey 145 func (a *announceData) sign(privKey *ecdsa.PrivateKey) { 146 rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td}) 147 sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey) 148 a.Update = a.Update.add("sign", sig) 149 } 150 151 // checkSignature verifies if the block announcement has a valid signature by the given pubKey 152 func (a *announceData) checkSignature(pubKey *ecdsa.PublicKey) error { 153 var sig []byte 154 if err := a.Update.decode().get("sign", &sig); err != nil { 155 return err 156 } 157 rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td}) 158 recPubkey, err := secp256k1.RecoverPubkey(crypto.Keccak256(rlp), sig) 159 if err != nil { 160 return err 161 } 162 pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y) 163 if bytes.Equal(pbytes, recPubkey) { 164 return nil 165 } 166 return errors.New("Wrong signature") 167 } 168 169 type blockInfo struct { 170 Hash common.Hash // Hash of one particular block being announced 171 Number uint64 // Number of one particular block being announced 172 Td *big.Int // Total difficulty of one particular block being announced 173 } 174 175 // getBlockHeadersData represents a block header query. 176 type getBlockHeadersData struct { 177 Origin hashOrNumber // Block from which to retrieve headers 178 Amount uint64 // Maximum number of headers to retrieve 179 Skip uint64 // Blocks to skip between consecutive headers 180 Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis) 181 } 182 183 // hashOrNumber is a combined field for specifying an origin block. 184 type hashOrNumber struct { 185 Hash common.Hash // Block hash from which to retrieve headers (excludes Number) 186 Number uint64 // Block hash from which to retrieve headers (excludes Hash) 187 } 188 189 // EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the 190 // two contained union fields. 191 func (hn *hashOrNumber) EncodeRLP(w io.Writer) error { 192 if hn.Hash == (common.Hash{}) { 193 return rlp.Encode(w, hn.Number) 194 } 195 if hn.Number != 0 { 196 return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number) 197 } 198 return rlp.Encode(w, hn.Hash) 199 } 200 201 // DecodeRLP is a specialized decoder for hashOrNumber to decode the contents 202 // into either a block hash or a block number. 203 func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error { 204 _, size, _ := s.Kind() 205 origin, err := s.Raw() 206 if err == nil { 207 switch { 208 case size == 32: 209 err = rlp.DecodeBytes(origin, &hn.Hash) 210 case size <= 8: 211 err = rlp.DecodeBytes(origin, &hn.Number) 212 default: 213 err = fmt.Errorf("invalid input size %d for origin", size) 214 } 215 } 216 return err 217 } 218 219 // CodeData is the network response packet for a node data retrieval. 220 type CodeData []struct { 221 Value []byte 222 } 223 224 type proofsData [][]rlp.RawValue 225 226 type txStatus struct { 227 Status core.TxStatus 228 Lookup *rawdb.TxLookupEntry `rlp:"nil"` 229 Error string 230 }