github.com/amazechain/amc@v0.1.3/internal/p2p/discover/v4wire/v4wire.go (about) 1 // Copyright 2020 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 v4wire implements the Discovery v4 Wire Protocol. 18 package v4wire 19 20 import ( 21 "bytes" 22 "crypto/ecdsa" 23 "crypto/elliptic" 24 "errors" 25 "fmt" 26 "github.com/amazechain/amc/common/crypto" 27 "github.com/amazechain/amc/common/math" 28 "github.com/amazechain/amc/internal/avm/rlp" 29 "github.com/amazechain/amc/internal/p2p/enode" 30 "github.com/amazechain/amc/internal/p2p/enr" 31 "math/big" 32 "net" 33 "time" 34 ) 35 36 // RPC packet types 37 const ( 38 PingPacket = iota + 1 // zero is 'reserved' 39 PongPacket 40 FindnodePacket 41 NeighborsPacket 42 ENRRequestPacket 43 ENRResponsePacket 44 ) 45 46 // RPC request structures 47 type ( 48 Ping struct { 49 Version uint 50 From, To Endpoint 51 Expiration uint64 52 ENRSeq uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868. 53 54 // Ignore additional fields (for forward compatibility). 55 Rest []rlp.RawValue `rlp:"tail"` 56 } 57 58 // Pong is the reply to ping. 59 Pong struct { 60 // This field should mirror the UDP envelope address 61 // of the ping packet, which provides a way to discover the 62 // external address (after NAT). 63 To Endpoint 64 ReplyTok []byte // This contains the hash of the ping packet. 65 Expiration uint64 // Absolute timestamp at which the packet becomes invalid. 66 ENRSeq uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868. 67 68 // Ignore additional fields (for forward compatibility). 69 Rest []rlp.RawValue `rlp:"tail"` 70 } 71 72 // Findnode is a query for nodes close to the given target. 73 Findnode struct { 74 Target Pubkey 75 Expiration uint64 76 // Ignore additional fields (for forward compatibility). 77 Rest []rlp.RawValue `rlp:"tail"` 78 } 79 80 // Neighbors is the reply to findnode. 81 Neighbors struct { 82 Nodes []Node 83 Expiration uint64 84 // Ignore additional fields (for forward compatibility). 85 Rest []rlp.RawValue `rlp:"tail"` 86 } 87 88 // ENRRequest queries for the remote node's record. 89 ENRRequest struct { 90 Expiration uint64 91 // Ignore additional fields (for forward compatibility). 92 Rest []rlp.RawValue `rlp:"tail"` 93 } 94 95 // ENRResponse is the reply to ENRRequest. 96 ENRResponse struct { 97 ReplyTok []byte // Hash of the ENRRequest packet. 98 Record enr.Record 99 // Ignore additional fields (for forward compatibility). 100 Rest []rlp.RawValue `rlp:"tail"` 101 } 102 ) 103 104 // MaxNeighbors is the maximum number of neighbor nodes in a Neighbors packet. 105 const MaxNeighbors = 12 106 107 // This code computes the MaxNeighbors constant value. 108 109 // func init() { 110 // var maxNeighbors int 111 // p := Neighbors{Expiration: ^uint64(0)} 112 // maxSizeNode := Node{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 113 // for n := 0; ; n++ { 114 // p.Nodes = append(p.Nodes, maxSizeNode) 115 // size, _, err := rlp.EncodeToReader(p) 116 // if err != nil { 117 // // If this ever happens, it will be caught by the unit tests. 118 // panic("cannot encode: " + err.Error()) 119 // } 120 // if headSize+size+1 >= 1280 { 121 // maxNeighbors = n 122 // break 123 // } 124 // } 125 // fmt.Println("maxNeighbors", maxNeighbors) 126 // } 127 128 // Pubkey represents an encoded 64-byte secp256k1 public key. 129 type Pubkey [64]byte 130 131 // ID returns the node ID corresponding to the public key. 132 func (e Pubkey) ID() enode.ID { 133 return enode.ID(crypto.Keccak256Hash(e[:])) 134 } 135 136 // Node represents information about a node. 137 type Node struct { 138 IP net.IP // len 4 for IPv4 or 16 for IPv6 139 UDP uint16 // for discovery protocol 140 TCP uint16 // for RLPx protocol 141 ID Pubkey 142 } 143 144 // Endpoint represents a network endpoint. 145 type Endpoint struct { 146 IP net.IP // len 4 for IPv4 or 16 for IPv6 147 UDP uint16 // for discovery protocol 148 TCP uint16 // for RLPx protocol 149 } 150 151 // NewEndpoint creates an endpoint. 152 func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint { 153 ip := net.IP{} 154 if ip4 := addr.IP.To4(); ip4 != nil { 155 ip = ip4 156 } else if ip6 := addr.IP.To16(); ip6 != nil { 157 ip = ip6 158 } 159 return Endpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} 160 } 161 162 type Packet interface { 163 // Name is the name of the package, for logging purposes. 164 Name() string 165 // Kind is the packet type, for logging purposes. 166 Kind() byte 167 } 168 169 func (req *Ping) Name() string { return "PING/v4" } 170 func (req *Ping) Kind() byte { return PingPacket } 171 172 func (req *Pong) Name() string { return "PONG/v4" } 173 func (req *Pong) Kind() byte { return PongPacket } 174 175 func (req *Findnode) Name() string { return "FINDNODE/v4" } 176 func (req *Findnode) Kind() byte { return FindnodePacket } 177 178 func (req *Neighbors) Name() string { return "NEIGHBORS/v4" } 179 func (req *Neighbors) Kind() byte { return NeighborsPacket } 180 181 func (req *ENRRequest) Name() string { return "ENRREQUEST/v4" } 182 func (req *ENRRequest) Kind() byte { return ENRRequestPacket } 183 184 func (req *ENRResponse) Name() string { return "ENRRESPONSE/v4" } 185 func (req *ENRResponse) Kind() byte { return ENRResponsePacket } 186 187 // Expired checks whether the given UNIX time stamp is in the past. 188 func Expired(ts uint64) bool { 189 return time.Unix(int64(ts), 0).Before(time.Now()) 190 } 191 192 // Encoder/decoder. 193 194 const ( 195 macSize = 32 196 sigSize = crypto.SignatureLength 197 headSize = macSize + sigSize // space of packet frame data 198 ) 199 200 var ( 201 ErrPacketTooSmall = errors.New("too small") 202 ErrBadHash = errors.New("bad hash") 203 ErrBadPoint = errors.New("invalid curve point") 204 ) 205 206 var headSpace = make([]byte, headSize) 207 208 // Decode reads a discovery v4 packet. 209 func Decode(input []byte) (Packet, Pubkey, []byte, error) { 210 if len(input) < headSize+1 { 211 return nil, Pubkey{}, nil, ErrPacketTooSmall 212 } 213 hash, sig, sigdata := input[:macSize], input[macSize:headSize], input[headSize:] 214 shouldhash := crypto.Keccak256(input[macSize:]) 215 if !bytes.Equal(hash, shouldhash) { 216 return nil, Pubkey{}, nil, ErrBadHash 217 } 218 fromKey, err := recoverNodeKey(crypto.Keccak256(input[headSize:]), sig) 219 if err != nil { 220 return nil, fromKey, hash, err 221 } 222 223 var req Packet 224 switch ptype := sigdata[0]; ptype { 225 case PingPacket: 226 req = new(Ping) 227 case PongPacket: 228 req = new(Pong) 229 case FindnodePacket: 230 req = new(Findnode) 231 case NeighborsPacket: 232 req = new(Neighbors) 233 case ENRRequestPacket: 234 req = new(ENRRequest) 235 case ENRResponsePacket: 236 req = new(ENRResponse) 237 default: 238 return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype) 239 } 240 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 241 err = s.Decode(req) 242 return req, fromKey, hash, err 243 } 244 245 // Encode encodes a discovery packet. 246 func Encode(priv *ecdsa.PrivateKey, req Packet) (packet, hash []byte, err error) { 247 b := new(bytes.Buffer) 248 b.Write(headSpace) 249 b.WriteByte(req.Kind()) 250 if err := rlp.Encode(b, req); err != nil { 251 return nil, nil, err 252 } 253 packet = b.Bytes() 254 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 255 if err != nil { 256 return nil, nil, err 257 } 258 copy(packet[macSize:], sig) 259 // Add the hash to the front. Note: this doesn't protect the packet in any way. 260 hash = crypto.Keccak256(packet[macSize:]) 261 copy(packet, hash) 262 return packet, hash, nil 263 } 264 265 // recoverNodeKey computes the public key used to sign the given hash from the signature. 266 func recoverNodeKey(hash, sig []byte) (key Pubkey, err error) { 267 pubkey, err := crypto.Ecrecover(hash, sig) 268 if err != nil { 269 return key, err 270 } 271 copy(key[:], pubkey[1:]) 272 return key, nil 273 } 274 275 // EncodePubkey encodes a secp256k1 public key. 276 func EncodePubkey(key *ecdsa.PublicKey) Pubkey { 277 var e Pubkey 278 math.ReadBits(key.X, e[:len(e)/2]) 279 math.ReadBits(key.Y, e[len(e)/2:]) 280 return e 281 } 282 283 // DecodePubkey reads an encoded secp256k1 public key. 284 func DecodePubkey(curve elliptic.Curve, e Pubkey) (*ecdsa.PublicKey, error) { 285 p := &ecdsa.PublicKey{Curve: curve, X: new(big.Int), Y: new(big.Int)} 286 half := len(e) / 2 287 p.X.SetBytes(e[:half]) 288 p.Y.SetBytes(e[half:]) 289 if !p.Curve.IsOnCurve(p.X, p.Y) { 290 return nil, ErrBadPoint 291 } 292 return p, nil 293 }