github.com/bcnmy/go-ethereum@v1.10.27/cmd/devp2p/internal/ethtest/types.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package ethtest 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "time" 23 24 "github.com/ethereum/go-ethereum/eth/protocols/eth" 25 "github.com/ethereum/go-ethereum/p2p" 26 "github.com/ethereum/go-ethereum/p2p/rlpx" 27 "github.com/ethereum/go-ethereum/rlp" 28 ) 29 30 type Message interface { 31 Code() int 32 ReqID() uint64 33 } 34 35 type Error struct { 36 err error 37 } 38 39 func (e *Error) Unwrap() error { return e.err } 40 func (e *Error) Error() string { return e.err.Error() } 41 func (e *Error) String() string { return e.Error() } 42 43 func (e *Error) Code() int { return -1 } 44 func (e *Error) ReqID() uint64 { return 0 } 45 46 func errorf(format string, args ...interface{}) *Error { 47 return &Error{fmt.Errorf(format, args...)} 48 } 49 50 // Hello is the RLP structure of the protocol handshake. 51 type Hello struct { 52 Version uint64 53 Name string 54 Caps []p2p.Cap 55 ListenPort uint64 56 ID []byte // secp256k1 public key 57 58 // Ignore additional fields (for forward compatibility). 59 Rest []rlp.RawValue `rlp:"tail"` 60 } 61 62 func (msg Hello) Code() int { return 0x00 } 63 func (msg Hello) ReqID() uint64 { return 0 } 64 65 // Disconnect is the RLP structure for a disconnect message. 66 type Disconnect struct { 67 Reason p2p.DiscReason 68 } 69 70 func (msg Disconnect) Code() int { return 0x01 } 71 func (msg Disconnect) ReqID() uint64 { return 0 } 72 73 type Ping struct{} 74 75 func (msg Ping) Code() int { return 0x02 } 76 func (msg Ping) ReqID() uint64 { return 0 } 77 78 type Pong struct{} 79 80 func (msg Pong) Code() int { return 0x03 } 81 func (msg Pong) ReqID() uint64 { return 0 } 82 83 // Status is the network packet for the status message for eth/64 and later. 84 type Status eth.StatusPacket 85 86 func (msg Status) Code() int { return 16 } 87 func (msg Status) ReqID() uint64 { return 0 } 88 89 // NewBlockHashes is the network packet for the block announcements. 90 type NewBlockHashes eth.NewBlockHashesPacket 91 92 func (msg NewBlockHashes) Code() int { return 17 } 93 func (msg NewBlockHashes) ReqID() uint64 { return 0 } 94 95 type Transactions eth.TransactionsPacket 96 97 func (msg Transactions) Code() int { return 18 } 98 func (msg Transactions) ReqID() uint64 { return 18 } 99 100 // GetBlockHeaders represents a block header query. 101 type GetBlockHeaders eth.GetBlockHeadersPacket66 102 103 func (msg GetBlockHeaders) Code() int { return 19 } 104 func (msg GetBlockHeaders) ReqID() uint64 { return msg.RequestId } 105 106 type BlockHeaders eth.BlockHeadersPacket66 107 108 func (msg BlockHeaders) Code() int { return 20 } 109 func (msg BlockHeaders) ReqID() uint64 { return msg.RequestId } 110 111 // GetBlockBodies represents a GetBlockBodies request 112 type GetBlockBodies eth.GetBlockBodiesPacket66 113 114 func (msg GetBlockBodies) Code() int { return 21 } 115 func (msg GetBlockBodies) ReqID() uint64 { return msg.RequestId } 116 117 // BlockBodies is the network packet for block content distribution. 118 type BlockBodies eth.BlockBodiesPacket66 119 120 func (msg BlockBodies) Code() int { return 22 } 121 func (msg BlockBodies) ReqID() uint64 { return msg.RequestId } 122 123 // NewBlock is the network packet for the block propagation message. 124 type NewBlock eth.NewBlockPacket 125 126 func (msg NewBlock) Code() int { return 23 } 127 func (msg NewBlock) ReqID() uint64 { return 0 } 128 129 // NewPooledTransactionHashes is the network packet for the tx hash propagation message. 130 type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket 131 132 func (msg NewPooledTransactionHashes) Code() int { return 24 } 133 func (msg NewPooledTransactionHashes) ReqID() uint64 { return 0 } 134 135 type GetPooledTransactions eth.GetPooledTransactionsPacket66 136 137 func (msg GetPooledTransactions) Code() int { return 25 } 138 func (msg GetPooledTransactions) ReqID() uint64 { return msg.RequestId } 139 140 type PooledTransactions eth.PooledTransactionsPacket66 141 142 func (msg PooledTransactions) Code() int { return 26 } 143 func (msg PooledTransactions) ReqID() uint64 { return msg.RequestId } 144 145 // Conn represents an individual connection with a peer 146 type Conn struct { 147 *rlpx.Conn 148 ourKey *ecdsa.PrivateKey 149 negotiatedProtoVersion uint 150 negotiatedSnapProtoVersion uint 151 ourHighestProtoVersion uint 152 ourHighestSnapProtoVersion uint 153 caps []p2p.Cap 154 } 155 156 // Read reads an eth66 packet from the connection. 157 func (c *Conn) Read() Message { 158 code, rawData, _, err := c.Conn.Read() 159 if err != nil { 160 return errorf("could not read from connection: %v", err) 161 } 162 163 var msg Message 164 switch int(code) { 165 case (Hello{}).Code(): 166 msg = new(Hello) 167 case (Ping{}).Code(): 168 msg = new(Ping) 169 case (Pong{}).Code(): 170 msg = new(Pong) 171 case (Disconnect{}).Code(): 172 msg = new(Disconnect) 173 case (Status{}).Code(): 174 msg = new(Status) 175 case (GetBlockHeaders{}).Code(): 176 ethMsg := new(eth.GetBlockHeadersPacket66) 177 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 178 return errorf("could not rlp decode message: %v", err) 179 } 180 return (*GetBlockHeaders)(ethMsg) 181 case (BlockHeaders{}).Code(): 182 ethMsg := new(eth.BlockHeadersPacket66) 183 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 184 return errorf("could not rlp decode message: %v", err) 185 } 186 return (*BlockHeaders)(ethMsg) 187 case (GetBlockBodies{}).Code(): 188 ethMsg := new(eth.GetBlockBodiesPacket66) 189 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 190 return errorf("could not rlp decode message: %v", err) 191 } 192 return (*GetBlockBodies)(ethMsg) 193 case (BlockBodies{}).Code(): 194 ethMsg := new(eth.BlockBodiesPacket66) 195 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 196 return errorf("could not rlp decode message: %v", err) 197 } 198 return (*BlockBodies)(ethMsg) 199 case (NewBlock{}).Code(): 200 msg = new(NewBlock) 201 case (NewBlockHashes{}).Code(): 202 msg = new(NewBlockHashes) 203 case (Transactions{}).Code(): 204 msg = new(Transactions) 205 case (NewPooledTransactionHashes{}).Code(): 206 msg = new(NewPooledTransactionHashes) 207 case (GetPooledTransactions{}.Code()): 208 ethMsg := new(eth.GetPooledTransactionsPacket66) 209 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 210 return errorf("could not rlp decode message: %v", err) 211 } 212 return (*GetPooledTransactions)(ethMsg) 213 case (PooledTransactions{}.Code()): 214 ethMsg := new(eth.PooledTransactionsPacket66) 215 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 216 return errorf("could not rlp decode message: %v", err) 217 } 218 return (*PooledTransactions)(ethMsg) 219 default: 220 msg = errorf("invalid message code: %d", code) 221 } 222 223 if msg != nil { 224 if err := rlp.DecodeBytes(rawData, msg); err != nil { 225 return errorf("could not rlp decode message: %v", err) 226 } 227 return msg 228 } 229 return errorf("invalid message: %s", string(rawData)) 230 } 231 232 // Write writes a eth packet to the connection. 233 func (c *Conn) Write(msg Message) error { 234 payload, err := rlp.EncodeToBytes(msg) 235 if err != nil { 236 return err 237 } 238 _, err = c.Conn.Write(uint64(msg.Code()), payload) 239 return err 240 } 241 242 // ReadSnap reads a snap/1 response with the given id from the connection. 243 func (c *Conn) ReadSnap(id uint64) (Message, error) { 244 respId := id + 1 245 start := time.Now() 246 for respId != id && time.Since(start) < timeout { 247 code, rawData, _, err := c.Conn.Read() 248 if err != nil { 249 return nil, fmt.Errorf("could not read from connection: %v", err) 250 } 251 var snpMsg interface{} 252 switch int(code) { 253 case (GetAccountRange{}).Code(): 254 snpMsg = new(GetAccountRange) 255 case (AccountRange{}).Code(): 256 snpMsg = new(AccountRange) 257 case (GetStorageRanges{}).Code(): 258 snpMsg = new(GetStorageRanges) 259 case (StorageRanges{}).Code(): 260 snpMsg = new(StorageRanges) 261 case (GetByteCodes{}).Code(): 262 snpMsg = new(GetByteCodes) 263 case (ByteCodes{}).Code(): 264 snpMsg = new(ByteCodes) 265 case (GetTrieNodes{}).Code(): 266 snpMsg = new(GetTrieNodes) 267 case (TrieNodes{}).Code(): 268 snpMsg = new(TrieNodes) 269 default: 270 //return nil, fmt.Errorf("invalid message code: %d", code) 271 continue 272 } 273 if err := rlp.DecodeBytes(rawData, snpMsg); err != nil { 274 return nil, fmt.Errorf("could not rlp decode message: %v", err) 275 } 276 return snpMsg.(Message), nil 277 } 278 return nil, fmt.Errorf("request timed out") 279 }