github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/cmd/devp2p/internal/ethtest/eth66_suite.go (about) 1 // Copyright 2021 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 ethtest 18 19 import ( 20 "time" 21 22 "github.com/fff-chain/go-fff/common" 23 "github.com/fff-chain/go-fff/core/types" 24 "github.com/fff-chain/go-fff/crypto" 25 "github.com/fff-chain/go-fff/eth/protocols/eth" 26 "github.com/fff-chain/go-fff/internal/utesting" 27 "github.com/fff-chain/go-fff/p2p" 28 ) 29 30 // Is_66 checks if the node supports the eth66 protocol version, 31 // and if not, exists the test suite 32 func (s *Suite) Is_66(t *utesting.T) { 33 conn := s.dial66(t) 34 conn.handshake(t) 35 if conn.negotiatedProtoVersion < 66 { 36 t.Fail() 37 } 38 } 39 40 // TestStatus_66 attempts to connect to the given node and exchange 41 // a status message with it on the eth66 protocol, and then check to 42 // make sure the chain head is correct. 43 func (s *Suite) TestStatus_66(t *utesting.T) { 44 conn := s.dial66(t) 45 defer conn.Close() 46 // get protoHandshake 47 conn.handshake(t) 48 // get status 49 switch msg := conn.statusExchange66(t, s.chain).(type) { 50 case *Status: 51 status := *msg 52 if status.ProtocolVersion != uint32(66) { 53 t.Fatalf("mismatch in version: wanted 66, got %d", status.ProtocolVersion) 54 } 55 t.Logf("got status message: %s", pretty.Sdump(msg)) 56 default: 57 t.Fatalf("unexpected: %s", pretty.Sdump(msg)) 58 } 59 } 60 61 // TestGetBlockHeaders_66 tests whether the given node can respond to 62 // an eth66 `GetBlockHeaders` request and that the response is accurate. 63 func (s *Suite) TestGetBlockHeaders_66(t *utesting.T) { 64 conn := s.setupConnection66(t) 65 defer conn.Close() 66 // get block headers 67 req := ð.GetBlockHeadersPacket66{ 68 RequestId: 3, 69 GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ 70 Origin: eth.HashOrNumber{ 71 Hash: s.chain.blocks[1].Hash(), 72 }, 73 Amount: 2, 74 Skip: 1, 75 Reverse: false, 76 }, 77 } 78 // write message 79 headers, err := s.getBlockHeaders66(conn, req, req.RequestId) 80 if err != nil { 81 t.Fatalf("could not get block headers: %v", err) 82 } 83 // check for correct headers 84 if !headersMatch(t, s.chain, headers) { 85 t.Fatal("received wrong header(s)") 86 } 87 } 88 89 // TestSimultaneousRequests_66 sends two simultaneous `GetBlockHeader` requests 90 // with different request IDs and checks to make sure the node responds with the correct 91 // headers per request. 92 func (s *Suite) TestSimultaneousRequests_66(t *utesting.T) { 93 // create two connections 94 conn := s.setupConnection66(t) 95 defer conn.Close() 96 // create two requests 97 req1 := ð.GetBlockHeadersPacket66{ 98 RequestId: 111, 99 GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ 100 Origin: eth.HashOrNumber{ 101 Hash: s.chain.blocks[1].Hash(), 102 }, 103 Amount: 2, 104 Skip: 1, 105 Reverse: false, 106 }, 107 } 108 req2 := ð.GetBlockHeadersPacket66{ 109 RequestId: 222, 110 GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ 111 Origin: eth.HashOrNumber{ 112 Hash: s.chain.blocks[1].Hash(), 113 }, 114 Amount: 4, 115 Skip: 1, 116 Reverse: false, 117 }, 118 } 119 // write first request 120 if err := conn.write66(req1, GetBlockHeaders{}.Code()); err != nil { 121 t.Fatalf("failed to write to connection: %v", err) 122 } 123 // write second request 124 if err := conn.write66(req2, GetBlockHeaders{}.Code()); err != nil { 125 t.Fatalf("failed to write to connection: %v", err) 126 } 127 // wait for responses 128 headers1, err := s.waitForBlockHeadersResponse66(conn, req1.RequestId) 129 if err != nil { 130 t.Fatalf("error while waiting for block headers: %v", err) 131 } 132 headers2, err := s.waitForBlockHeadersResponse66(conn, req2.RequestId) 133 if err != nil { 134 t.Fatalf("error while waiting for block headers: %v", err) 135 } 136 // check headers of both responses 137 if !headersMatch(t, s.chain, headers1) { 138 t.Fatalf("wrong header(s) in response to req1: got %v", headers1) 139 } 140 if !headersMatch(t, s.chain, headers2) { 141 t.Fatalf("wrong header(s) in response to req2: got %v", headers2) 142 } 143 } 144 145 // TestBroadcast_66 tests whether a block announcement is correctly 146 // propagated to the given node's peer(s) on the eth66 protocol. 147 func (s *Suite) TestBroadcast_66(t *utesting.T) { 148 s.sendNextBlock66(t) 149 } 150 151 // TestGetBlockBodies_66 tests whether the given node can respond to 152 // a `GetBlockBodies` request and that the response is accurate over 153 // the eth66 protocol. 154 func (s *Suite) TestGetBlockBodies_66(t *utesting.T) { 155 conn := s.setupConnection66(t) 156 defer conn.Close() 157 // create block bodies request 158 id := uint64(55) 159 req := ð.GetBlockBodiesPacket66{ 160 RequestId: id, 161 GetBlockBodiesPacket: eth.GetBlockBodiesPacket{ 162 s.chain.blocks[54].Hash(), 163 s.chain.blocks[75].Hash(), 164 }, 165 } 166 if err := conn.write66(req, GetBlockBodies{}.Code()); err != nil { 167 t.Fatalf("could not write to connection: %v", err) 168 } 169 170 reqID, msg := conn.readAndServe66(s.chain, timeout) 171 switch msg := msg.(type) { 172 case BlockBodies: 173 if reqID != req.RequestId { 174 t.Fatalf("request ID mismatch: wanted %d, got %d", req.RequestId, reqID) 175 } 176 t.Logf("received %d block bodies", len(msg)) 177 default: 178 t.Fatalf("unexpected: %s", pretty.Sdump(msg)) 179 } 180 } 181 182 // TestLargeAnnounce_66 tests the announcement mechanism with a large block. 183 func (s *Suite) TestLargeAnnounce_66(t *utesting.T) { 184 nextBlock := len(s.chain.blocks) 185 blocks := []*NewBlock{ 186 { 187 Block: largeBlock(), 188 TD: s.fullChain.TD(nextBlock + 1), 189 }, 190 { 191 Block: s.fullChain.blocks[nextBlock], 192 TD: largeNumber(2), 193 }, 194 { 195 Block: largeBlock(), 196 TD: largeNumber(2), 197 }, 198 { 199 Block: s.fullChain.blocks[nextBlock], 200 TD: s.fullChain.TD(nextBlock + 1), 201 }, 202 } 203 204 for i, blockAnnouncement := range blocks[0:3] { 205 t.Logf("Testing malicious announcement: %v\n", i) 206 sendConn := s.setupConnection66(t) 207 if err := sendConn.Write(blockAnnouncement); err != nil { 208 t.Fatalf("could not write to connection: %v", err) 209 } 210 // Invalid announcement, check that peer disconnected 211 switch msg := sendConn.ReadAndServe(s.chain, time.Second*8).(type) { 212 case *Disconnect: 213 case *Error: 214 break 215 default: 216 t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg)) 217 } 218 sendConn.Close() 219 } 220 // Test the last block as a valid block 221 s.sendNextBlock66(t) 222 } 223 224 func (s *Suite) TestOldAnnounce_66(t *utesting.T) { 225 sendConn, recvConn := s.setupConnection66(t), s.setupConnection66(t) 226 defer sendConn.Close() 227 defer recvConn.Close() 228 229 s.oldAnnounce(t, sendConn, recvConn) 230 } 231 232 // TestMaliciousHandshake_66 tries to send malicious data during the handshake. 233 func (s *Suite) TestMaliciousHandshake_66(t *utesting.T) { 234 conn := s.dial66(t) 235 defer conn.Close() 236 // write hello to client 237 pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:] 238 handshakes := []*Hello{ 239 { 240 Version: 5, 241 Caps: []p2p.Cap{ 242 {Name: largeString(2), Version: 66}, 243 }, 244 ID: pub0, 245 }, 246 { 247 Version: 5, 248 Caps: []p2p.Cap{ 249 {Name: "eth", Version: 64}, 250 {Name: "eth", Version: 65}, 251 {Name: "eth", Version: 66}, 252 }, 253 ID: append(pub0, byte(0)), 254 }, 255 { 256 Version: 5, 257 Caps: []p2p.Cap{ 258 {Name: "eth", Version: 64}, 259 {Name: "eth", Version: 65}, 260 {Name: "eth", Version: 66}, 261 }, 262 ID: append(pub0, pub0...), 263 }, 264 { 265 Version: 5, 266 Caps: []p2p.Cap{ 267 {Name: "eth", Version: 64}, 268 {Name: "eth", Version: 65}, 269 {Name: "eth", Version: 66}, 270 }, 271 ID: largeBuffer(2), 272 }, 273 { 274 Version: 5, 275 Caps: []p2p.Cap{ 276 {Name: largeString(2), Version: 66}, 277 }, 278 ID: largeBuffer(2), 279 }, 280 } 281 for i, handshake := range handshakes { 282 t.Logf("Testing malicious handshake %v\n", i) 283 // Init the handshake 284 if err := conn.Write(handshake); err != nil { 285 t.Fatalf("could not write to connection: %v", err) 286 } 287 // check that the peer disconnected 288 timeout := 20 * time.Second 289 // Discard one hello 290 for i := 0; i < 2; i++ { 291 switch msg := conn.ReadAndServe(s.chain, timeout).(type) { 292 case *Disconnect: 293 case *Error: 294 case *Hello: 295 // Hello's are sent concurrently, so ignore them 296 continue 297 default: 298 t.Fatalf("unexpected: %s", pretty.Sdump(msg)) 299 } 300 } 301 // Dial for the next round 302 conn = s.dial66(t) 303 } 304 } 305 306 // TestMaliciousStatus_66 sends a status package with a large total difficulty. 307 func (s *Suite) TestMaliciousStatus_66(t *utesting.T) { 308 conn := s.dial66(t) 309 defer conn.Close() 310 // get protoHandshake 311 conn.handshake(t) 312 status := &Status{ 313 ProtocolVersion: uint32(66), 314 NetworkID: s.chain.chainConfig.ChainID.Uint64(), 315 TD: largeNumber(2), 316 Head: s.chain.blocks[s.chain.Len()-1].Hash(), 317 Genesis: s.chain.blocks[0].Hash(), 318 ForkID: s.chain.ForkID(), 319 } 320 // get status 321 switch msg := conn.statusExchange(t, s.chain, status).(type) { 322 case *Status: 323 t.Logf("%+v\n", msg) 324 default: 325 t.Fatalf("expected status, got: %#v ", msg) 326 } 327 // wait for disconnect 328 switch msg := conn.ReadAndServe(s.chain, timeout).(type) { 329 case *Disconnect: 330 case *Error: 331 return 332 default: 333 t.Fatalf("expected disconnect, got: %s", pretty.Sdump(msg)) 334 } 335 } 336 337 func (s *Suite) TestTransaction_66(t *utesting.T) { 338 tests := []*types.Transaction{ 339 getNextTxFromChain(t, s), 340 unknownTx(t, s), 341 } 342 for i, tx := range tests { 343 t.Logf("Testing tx propagation: %v\n", i) 344 sendSuccessfulTx66(t, s, tx) 345 } 346 } 347 348 func (s *Suite) TestMaliciousTx_66(t *utesting.T) { 349 badTxs := []*types.Transaction{ 350 getOldTxFromChain(t, s), 351 invalidNonceTx(t, s), 352 hugeAmount(t, s), 353 hugeGasPrice(t, s), 354 hugeData(t, s), 355 } 356 sendConn := s.setupConnection66(t) 357 defer sendConn.Close() 358 // set up receiving connection before sending txs to make sure 359 // no announcements are missed 360 recvConn := s.setupConnection66(t) 361 defer recvConn.Close() 362 363 for i, tx := range badTxs { 364 t.Logf("Testing malicious tx propagation: %v\n", i) 365 if err := sendConn.Write(&Transactions{tx}); err != nil { 366 t.Fatalf("could not write to connection: %v", err) 367 } 368 369 } 370 // check to make sure bad txs aren't propagated 371 waitForTxPropagation(t, s, badTxs, recvConn) 372 } 373 374 // TestZeroRequestID_66 checks that a request ID of zero is still handled 375 // by the node. 376 func (s *Suite) TestZeroRequestID_66(t *utesting.T) { 377 conn := s.setupConnection66(t) 378 defer conn.Close() 379 380 req := ð.GetBlockHeadersPacket66{ 381 RequestId: 0, 382 GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ 383 Origin: eth.HashOrNumber{ 384 Number: 0, 385 }, 386 Amount: 2, 387 }, 388 } 389 headers, err := s.getBlockHeaders66(conn, req, req.RequestId) 390 if err != nil { 391 t.Fatalf("could not get block headers: %v", err) 392 } 393 if !headersMatch(t, s.chain, headers) { 394 t.Fatal("received wrong header(s)") 395 } 396 } 397 398 // TestSameRequestID_66 sends two requests with the same request ID 399 // concurrently to a single node. 400 func (s *Suite) TestSameRequestID_66(t *utesting.T) { 401 conn := s.setupConnection66(t) 402 // create two requests with the same request ID 403 reqID := uint64(1234) 404 request1 := ð.GetBlockHeadersPacket66{ 405 RequestId: reqID, 406 GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ 407 Origin: eth.HashOrNumber{ 408 Number: 1, 409 }, 410 Amount: 2, 411 }, 412 } 413 request2 := ð.GetBlockHeadersPacket66{ 414 RequestId: reqID, 415 GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ 416 Origin: eth.HashOrNumber{ 417 Number: 33, 418 }, 419 Amount: 2, 420 }, 421 } 422 // write the first request 423 err := conn.write66(request1, GetBlockHeaders{}.Code()) 424 if err != nil { 425 t.Fatalf("could not write to connection: %v", err) 426 } 427 // perform second request 428 headers2, err := s.getBlockHeaders66(conn, request2, reqID) 429 if err != nil { 430 t.Fatalf("could not get block headers: %v", err) 431 return 432 } 433 // wait for response to first request 434 headers1, err := s.waitForBlockHeadersResponse66(conn, reqID) 435 if err != nil { 436 t.Fatalf("could not get BlockHeaders response: %v", err) 437 } 438 // check if headers match 439 if !headersMatch(t, s.chain, headers1) || !headersMatch(t, s.chain, headers2) { 440 t.Fatal("received wrong header(s)") 441 } 442 } 443 444 // TestLargeTxRequest_66 tests whether a node can fulfill a large GetPooledTransactions 445 // request. 446 func (s *Suite) TestLargeTxRequest_66(t *utesting.T) { 447 // send the next block to ensure the node is no longer syncing and is able to accept 448 // txs 449 s.sendNextBlock66(t) 450 // send 2000 transactions to the node 451 hashMap, txs := generateTxs(t, s, 2000) 452 sendConn := s.setupConnection66(t) 453 defer sendConn.Close() 454 455 sendMultipleSuccessfulTxs(t, s, sendConn, txs) 456 // set up connection to receive to ensure node is peered with the receiving connection 457 // before tx request is sent 458 recvConn := s.setupConnection66(t) 459 defer recvConn.Close() 460 // create and send pooled tx request 461 hashes := make([]common.Hash, 0) 462 for _, hash := range hashMap { 463 hashes = append(hashes, hash) 464 } 465 getTxReq := ð.GetPooledTransactionsPacket66{ 466 RequestId: 1234, 467 GetPooledTransactionsPacket: hashes, 468 } 469 if err := recvConn.write66(getTxReq, GetPooledTransactions{}.Code()); err != nil { 470 t.Fatalf("could not write to conn: %v", err) 471 } 472 // check that all received transactions match those that were sent to node 473 switch msg := recvConn.waitForResponse(s.chain, timeout, getTxReq.RequestId).(type) { 474 case PooledTransactions: 475 for _, gotTx := range msg { 476 if _, exists := hashMap[gotTx.Hash()]; !exists { 477 t.Fatalf("unexpected tx received: %v", gotTx.Hash()) 478 } 479 } 480 default: 481 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 482 } 483 } 484 485 // TestNewPooledTxs_66 tests whether a node will do a GetPooledTransactions 486 // request upon receiving a NewPooledTransactionHashes announcement. 487 func (s *Suite) TestNewPooledTxs_66(t *utesting.T) { 488 // send the next block to ensure the node is no longer syncing and is able to accept 489 // txs 490 s.sendNextBlock66(t) 491 // generate 50 txs 492 hashMap, _ := generateTxs(t, s, 50) 493 // create new pooled tx hashes announcement 494 hashes := make([]common.Hash, 0) 495 for _, hash := range hashMap { 496 hashes = append(hashes, hash) 497 } 498 announce := NewPooledTransactionHashes(hashes) 499 // send announcement 500 conn := s.setupConnection66(t) 501 defer conn.Close() 502 if err := conn.Write(announce); err != nil { 503 t.Fatalf("could not write to connection: %v", err) 504 } 505 // wait for GetPooledTxs request 506 for { 507 _, msg := conn.readAndServe66(s.chain, timeout) 508 switch msg := msg.(type) { 509 case GetPooledTransactions: 510 if len(msg) != len(hashes) { 511 t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg)) 512 } 513 return 514 case *NewPooledTransactionHashes, *NewBlock, *NewBlockHashes: 515 // ignore propagated txs and blocks from old tests 516 continue 517 default: 518 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 519 } 520 } 521 }