github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/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/tirogen/go-ethereum/eth/protocols/eth" 25 "github.com/tirogen/go-ethereum/p2p" 26 "github.com/tirogen/go-ethereum/p2p/rlpx" 27 "github.com/tirogen/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 // NewPooledTransactionHashes66 is the network packet for the tx hash propagation message. 130 type NewPooledTransactionHashes66 eth.NewPooledTransactionHashesPacket66 131 132 func (msg NewPooledTransactionHashes66) Code() int { return 24 } 133 func (msg NewPooledTransactionHashes66) ReqID() uint64 { return 0 } 134 135 // NewPooledTransactionHashes is the network packet for the tx hash propagation message. 136 type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket68 137 138 func (msg NewPooledTransactionHashes) Code() int { return 24 } 139 func (msg NewPooledTransactionHashes) ReqID() uint64 { return 0 } 140 141 type GetPooledTransactions eth.GetPooledTransactionsPacket66 142 143 func (msg GetPooledTransactions) Code() int { return 25 } 144 func (msg GetPooledTransactions) ReqID() uint64 { return msg.RequestId } 145 146 type PooledTransactions eth.PooledTransactionsPacket66 147 148 func (msg PooledTransactions) Code() int { return 26 } 149 func (msg PooledTransactions) ReqID() uint64 { return msg.RequestId } 150 151 // Conn represents an individual connection with a peer 152 type Conn struct { 153 *rlpx.Conn 154 ourKey *ecdsa.PrivateKey 155 negotiatedProtoVersion uint 156 negotiatedSnapProtoVersion uint 157 ourHighestProtoVersion uint 158 ourHighestSnapProtoVersion uint 159 caps []p2p.Cap 160 } 161 162 // Read reads an eth66 packet from the connection. 163 func (c *Conn) Read() Message { 164 code, rawData, _, err := c.Conn.Read() 165 if err != nil { 166 return errorf("could not read from connection: %v", err) 167 } 168 169 var msg Message 170 switch int(code) { 171 case (Hello{}).Code(): 172 msg = new(Hello) 173 case (Ping{}).Code(): 174 msg = new(Ping) 175 case (Pong{}).Code(): 176 msg = new(Pong) 177 case (Disconnect{}).Code(): 178 msg = new(Disconnect) 179 case (Status{}).Code(): 180 msg = new(Status) 181 case (GetBlockHeaders{}).Code(): 182 ethMsg := new(eth.GetBlockHeadersPacket66) 183 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 184 return errorf("could not rlp decode message: %v", err) 185 } 186 return (*GetBlockHeaders)(ethMsg) 187 case (BlockHeaders{}).Code(): 188 ethMsg := new(eth.BlockHeadersPacket66) 189 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 190 return errorf("could not rlp decode message: %v", err) 191 } 192 return (*BlockHeaders)(ethMsg) 193 case (GetBlockBodies{}).Code(): 194 ethMsg := new(eth.GetBlockBodiesPacket66) 195 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 196 return errorf("could not rlp decode message: %v", err) 197 } 198 return (*GetBlockBodies)(ethMsg) 199 case (BlockBodies{}).Code(): 200 ethMsg := new(eth.BlockBodiesPacket66) 201 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 202 return errorf("could not rlp decode message: %v", err) 203 } 204 return (*BlockBodies)(ethMsg) 205 case (NewBlock{}).Code(): 206 msg = new(NewBlock) 207 case (NewBlockHashes{}).Code(): 208 msg = new(NewBlockHashes) 209 case (Transactions{}).Code(): 210 msg = new(Transactions) 211 case (NewPooledTransactionHashes66{}).Code(): 212 // Try decoding to eth68 213 ethMsg := new(NewPooledTransactionHashes) 214 if err := rlp.DecodeBytes(rawData, ethMsg); err == nil { 215 return ethMsg 216 } 217 msg = new(NewPooledTransactionHashes66) 218 case (GetPooledTransactions{}.Code()): 219 ethMsg := new(eth.GetPooledTransactionsPacket66) 220 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 221 return errorf("could not rlp decode message: %v", err) 222 } 223 return (*GetPooledTransactions)(ethMsg) 224 case (PooledTransactions{}.Code()): 225 ethMsg := new(eth.PooledTransactionsPacket66) 226 if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { 227 return errorf("could not rlp decode message: %v", err) 228 } 229 return (*PooledTransactions)(ethMsg) 230 default: 231 msg = errorf("invalid message code: %d", code) 232 } 233 234 if msg != nil { 235 if err := rlp.DecodeBytes(rawData, msg); err != nil { 236 return errorf("could not rlp decode message: %v", err) 237 } 238 return msg 239 } 240 return errorf("invalid message: %s", string(rawData)) 241 } 242 243 // Write writes a eth packet to the connection. 244 func (c *Conn) Write(msg Message) error { 245 payload, err := rlp.EncodeToBytes(msg) 246 if err != nil { 247 return err 248 } 249 _, err = c.Conn.Write(uint64(msg.Code()), payload) 250 return err 251 } 252 253 // ReadSnap reads a snap/1 response with the given id from the connection. 254 func (c *Conn) ReadSnap(id uint64) (Message, error) { 255 respId := id + 1 256 start := time.Now() 257 for respId != id && time.Since(start) < timeout { 258 code, rawData, _, err := c.Conn.Read() 259 if err != nil { 260 return nil, fmt.Errorf("could not read from connection: %v", err) 261 } 262 var snpMsg interface{} 263 switch int(code) { 264 case (GetAccountRange{}).Code(): 265 snpMsg = new(GetAccountRange) 266 case (AccountRange{}).Code(): 267 snpMsg = new(AccountRange) 268 case (GetStorageRanges{}).Code(): 269 snpMsg = new(GetStorageRanges) 270 case (StorageRanges{}).Code(): 271 snpMsg = new(StorageRanges) 272 case (GetByteCodes{}).Code(): 273 snpMsg = new(GetByteCodes) 274 case (ByteCodes{}).Code(): 275 snpMsg = new(ByteCodes) 276 case (GetTrieNodes{}).Code(): 277 snpMsg = new(GetTrieNodes) 278 case (TrieNodes{}).Code(): 279 snpMsg = new(TrieNodes) 280 default: 281 //return nil, fmt.Errorf("invalid message code: %d", code) 282 continue 283 } 284 if err := rlp.DecodeBytes(rawData, snpMsg); err != nil { 285 return nil, fmt.Errorf("could not rlp decode message: %v", err) 286 } 287 return snpMsg.(Message), nil 288 } 289 return nil, fmt.Errorf("request timed out") 290 }