github.com/theQRL/go-zond@v0.1.1/cmd/devp2p/internal/ethtest/suite.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 "time" 21 22 "github.com/theQRL/go-zond/common" 23 "github.com/theQRL/go-zond/internal/utesting" 24 "github.com/theQRL/go-zond/p2p/enode" 25 "github.com/theQRL/go-zond/zond/protocols/zond" 26 ) 27 28 // Suite represents a structure used to test a node's conformance 29 // to the zond protocol. 30 type Suite struct { 31 Dest *enode.Node 32 33 chain *Chain 34 fullChain *Chain 35 } 36 37 // NewSuite creates and returns a new zond-test suite that can 38 // be used to test the given node against the given blockchain 39 // data. 40 func NewSuite(dest *enode.Node, chainfile string, genesisfile string) (*Suite, error) { 41 chain, err := loadChain(chainfile, genesisfile) 42 if err != nil { 43 return nil, err 44 } 45 return &Suite{ 46 Dest: dest, 47 chain: chain.Shorten(1000), 48 fullChain: chain, 49 }, nil 50 } 51 52 func (s *Suite) EthTests() []utesting.Test { 53 return []utesting.Test{ 54 // status 55 {Name: "TestStatus", Fn: s.TestStatus}, 56 // get block headers 57 {Name: "TestGetBlockHeaders", Fn: s.TestGetBlockHeaders}, 58 {Name: "TestSimultaneousRequests", Fn: s.TestSimultaneousRequests}, 59 {Name: "TestSameRequestID", Fn: s.TestSameRequestID}, 60 {Name: "TestZeroRequestID", Fn: s.TestZeroRequestID}, 61 // get block bodies 62 {Name: "TestGetBlockBodies", Fn: s.TestGetBlockBodies}, 63 // broadcast 64 {Name: "TestBroadcast", Fn: s.TestBroadcast}, 65 {Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce}, 66 {Name: "TestOldAnnounce", Fn: s.TestOldAnnounce}, 67 {Name: "TestBlockHashAnnounce", Fn: s.TestBlockHashAnnounce}, 68 // malicious handshakes + status 69 {Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake}, 70 {Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus}, 71 // test transactions 72 {Name: "TestTransaction", Fn: s.TestTransaction}, 73 {Name: "TestMaliciousTx", Fn: s.TestMaliciousTx}, 74 {Name: "TestLargeTxRequest", Fn: s.TestLargeTxRequest}, 75 {Name: "TestNewPooledTxs", Fn: s.TestNewPooledTxs}, 76 } 77 } 78 79 func (s *Suite) SnapTests() []utesting.Test { 80 return []utesting.Test{ 81 {Name: "TestSnapStatus", Fn: s.TestSnapStatus}, 82 {Name: "TestSnapAccountRange", Fn: s.TestSnapGetAccountRange}, 83 {Name: "TestSnapGetByteCodes", Fn: s.TestSnapGetByteCodes}, 84 {Name: "TestSnapGetTrieNodes", Fn: s.TestSnapTrieNodes}, 85 {Name: "TestSnapGetStorageRanges", Fn: s.TestSnapGetStorageRanges}, 86 } 87 } 88 89 // TestStatus attempts to connect to the given node and exchange 90 // a status message with it on the zond protocol. 91 func (s *Suite) TestStatus(t *utesting.T) { 92 conn, err := s.dial() 93 if err != nil { 94 t.Fatalf("dial failed: %v", err) 95 } 96 defer conn.Close() 97 if err := conn.peer(s.chain, nil); err != nil { 98 t.Fatalf("peering failed: %v", err) 99 } 100 } 101 102 // TestGetBlockHeaders tests whether the given node can respond to 103 // an zond `GetBlockHeaders` request and that the response is accurate. 104 func (s *Suite) TestGetBlockHeaders(t *utesting.T) { 105 conn, err := s.dial() 106 if err != nil { 107 t.Fatalf("dial failed: %v", err) 108 } 109 defer conn.Close() 110 if err = conn.peer(s.chain, nil); err != nil { 111 t.Fatalf("peering failed: %v", err) 112 } 113 // write request 114 req := &GetBlockHeaders{ 115 GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{ 116 Origin: zond.HashOrNumber{Hash: s.chain.blocks[1].Hash()}, 117 Amount: 2, 118 Skip: 1, 119 Reverse: false, 120 }, 121 } 122 headers, err := conn.headersRequest(req, s.chain, 33) 123 if err != nil { 124 t.Fatalf("could not get block headers: %v", err) 125 } 126 // check for correct headers 127 expected, err := s.chain.GetHeaders(req) 128 if err != nil { 129 t.Fatalf("failed to get headers for given request: %v", err) 130 } 131 if !headersMatch(expected, headers) { 132 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers) 133 } 134 } 135 136 // TestSimultaneousRequests sends two simultaneous `GetBlockHeader` requests from 137 // the same connection with different request IDs and checks to make sure the node 138 // responds with the correct headers per request. 139 func (s *Suite) TestSimultaneousRequests(t *utesting.T) { 140 // create a connection 141 conn, err := s.dial() 142 if err != nil { 143 t.Fatalf("dial failed: %v", err) 144 } 145 defer conn.Close() 146 if err := conn.peer(s.chain, nil); err != nil { 147 t.Fatalf("peering failed: %v", err) 148 } 149 150 // create two requests 151 req1 := &GetBlockHeaders{ 152 RequestId: uint64(111), 153 GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{ 154 Origin: zond.HashOrNumber{ 155 Hash: s.chain.blocks[1].Hash(), 156 }, 157 Amount: 2, 158 Skip: 1, 159 Reverse: false, 160 }, 161 } 162 req2 := &GetBlockHeaders{ 163 RequestId: uint64(222), 164 GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{ 165 Origin: zond.HashOrNumber{ 166 Hash: s.chain.blocks[1].Hash(), 167 }, 168 Amount: 4, 169 Skip: 1, 170 Reverse: false, 171 }, 172 } 173 174 // write the first request 175 if err := conn.Write(req1); err != nil { 176 t.Fatalf("failed to write to connection: %v", err) 177 } 178 // write the second request 179 if err := conn.Write(req2); err != nil { 180 t.Fatalf("failed to write to connection: %v", err) 181 } 182 183 // wait for responses 184 msg := conn.waitForResponse(s.chain, timeout, req1.RequestId) 185 headers1, ok := msg.(*BlockHeaders) 186 if !ok { 187 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 188 } 189 msg = conn.waitForResponse(s.chain, timeout, req2.RequestId) 190 headers2, ok := msg.(*BlockHeaders) 191 if !ok { 192 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 193 } 194 195 // check received headers for accuracy 196 expected1, err := s.chain.GetHeaders(req1) 197 if err != nil { 198 t.Fatalf("failed to get expected headers for request 1: %v", err) 199 } 200 expected2, err := s.chain.GetHeaders(req2) 201 if err != nil { 202 t.Fatalf("failed to get expected headers for request 2: %v", err) 203 } 204 if !headersMatch(expected1, headers1.BlockHeadersPacket) { 205 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected1, headers1) 206 } 207 if !headersMatch(expected2, headers2.BlockHeadersPacket) { 208 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected2, headers2) 209 } 210 } 211 212 // TestSameRequestID sends two requests with the same request ID to a 213 // single node. 214 func (s *Suite) TestSameRequestID(t *utesting.T) { 215 conn, err := s.dial() 216 if err != nil { 217 t.Fatalf("dial failed: %v", err) 218 } 219 defer conn.Close() 220 if err := conn.peer(s.chain, nil); err != nil { 221 t.Fatalf("peering failed: %v", err) 222 } 223 // create requests 224 reqID := uint64(1234) 225 request1 := &GetBlockHeaders{ 226 RequestId: reqID, 227 GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{ 228 Origin: zond.HashOrNumber{ 229 Number: 1, 230 }, 231 Amount: 2, 232 }, 233 } 234 request2 := &GetBlockHeaders{ 235 RequestId: reqID, 236 GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{ 237 Origin: zond.HashOrNumber{ 238 Number: 33, 239 }, 240 Amount: 2, 241 }, 242 } 243 244 // write the requests 245 if err = conn.Write(request1); err != nil { 246 t.Fatalf("failed to write to connection: %v", err) 247 } 248 if err = conn.Write(request2); err != nil { 249 t.Fatalf("failed to write to connection: %v", err) 250 } 251 252 // wait for responses 253 msg := conn.waitForResponse(s.chain, timeout, reqID) 254 headers1, ok := msg.(*BlockHeaders) 255 if !ok { 256 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 257 } 258 msg = conn.waitForResponse(s.chain, timeout, reqID) 259 headers2, ok := msg.(*BlockHeaders) 260 if !ok { 261 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 262 } 263 264 // check if headers match 265 expected1, err := s.chain.GetHeaders(request1) 266 if err != nil { 267 t.Fatalf("failed to get expected block headers: %v", err) 268 } 269 expected2, err := s.chain.GetHeaders(request2) 270 if err != nil { 271 t.Fatalf("failed to get expected block headers: %v", err) 272 } 273 if !headersMatch(expected1, headers1.BlockHeadersPacket) { 274 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected1, headers1) 275 } 276 if !headersMatch(expected2, headers2.BlockHeadersPacket) { 277 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected2, headers2) 278 } 279 } 280 281 // TestZeroRequestID checks that a message with a request ID of zero is still handled 282 // by the node. 283 func (s *Suite) TestZeroRequestID(t *utesting.T) { 284 conn, err := s.dial() 285 if err != nil { 286 t.Fatalf("dial failed: %v", err) 287 } 288 defer conn.Close() 289 if err := conn.peer(s.chain, nil); err != nil { 290 t.Fatalf("peering failed: %v", err) 291 } 292 req := &GetBlockHeaders{ 293 GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{ 294 Origin: zond.HashOrNumber{Number: 0}, 295 Amount: 2, 296 }, 297 } 298 headers, err := conn.headersRequest(req, s.chain, 0) 299 if err != nil { 300 t.Fatalf("failed to get block headers: %v", err) 301 } 302 expected, err := s.chain.GetHeaders(req) 303 if err != nil { 304 t.Fatalf("failed to get expected block headers: %v", err) 305 } 306 if !headersMatch(expected, headers) { 307 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers) 308 } 309 } 310 311 // TestGetBlockBodies tests whether the given node can respond to 312 // a `GetBlockBodies` request and that the response is accurate. 313 func (s *Suite) TestGetBlockBodies(t *utesting.T) { 314 conn, err := s.dial() 315 if err != nil { 316 t.Fatalf("dial failed: %v", err) 317 } 318 defer conn.Close() 319 if err := conn.peer(s.chain, nil); err != nil { 320 t.Fatalf("peering failed: %v", err) 321 } 322 // create block bodies request 323 req := &GetBlockBodies{ 324 RequestId: uint64(55), 325 GetBlockBodiesPacket: zond.GetBlockBodiesPacket{ 326 s.chain.blocks[54].Hash(), 327 s.chain.blocks[75].Hash(), 328 }, 329 } 330 if err := conn.Write(req); err != nil { 331 t.Fatalf("could not write to connection: %v", err) 332 } 333 // wait for block bodies response 334 msg := conn.waitForResponse(s.chain, timeout, req.RequestId) 335 resp, ok := msg.(*BlockBodies) 336 if !ok { 337 t.Fatalf("unexpected: %s", pretty.Sdump(msg)) 338 } 339 bodies := resp.BlockBodiesPacket 340 t.Logf("received %d block bodies", len(bodies)) 341 if len(bodies) != len(req.GetBlockBodiesPacket) { 342 t.Fatalf("wrong bodies in response: expected %d bodies, "+ 343 "got %d", len(req.GetBlockBodiesPacket), len(bodies)) 344 } 345 } 346 347 // TestBroadcast tests whether a block announcement is correctly 348 // propagated to the node's peers. 349 func (s *Suite) TestBroadcast(t *utesting.T) { 350 if err := s.sendNextBlock(); err != nil { 351 t.Fatalf("block broadcast failed: %v", err) 352 } 353 } 354 355 // TestLargeAnnounce tests the announcement mechanism with a large block. 356 func (s *Suite) TestLargeAnnounce(t *utesting.T) { 357 nextBlock := len(s.chain.blocks) 358 blocks := []*NewBlock{ 359 { 360 Block: largeBlock(), 361 TD: s.fullChain.TotalDifficultyAt(nextBlock), 362 }, 363 { 364 Block: s.fullChain.blocks[nextBlock], 365 TD: largeNumber(2), 366 }, 367 { 368 Block: largeBlock(), 369 TD: largeNumber(2), 370 }, 371 } 372 373 for i, blockAnnouncement := range blocks[0:3] { 374 t.Logf("Testing malicious announcement: %v\n", i) 375 conn, err := s.dial() 376 if err != nil { 377 t.Fatalf("dial failed: %v", err) 378 } 379 if err := conn.peer(s.chain, nil); err != nil { 380 t.Fatalf("peering failed: %v", err) 381 } 382 if err := conn.Write(blockAnnouncement); err != nil { 383 t.Fatalf("could not write to connection: %v", err) 384 } 385 // Invalid announcement, check that peer disconnected 386 switch msg := conn.readAndServe(s.chain, 8*time.Second).(type) { 387 case *Disconnect: 388 case *Error: 389 break 390 default: 391 t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg)) 392 } 393 conn.Close() 394 } 395 // Test the last block as a valid block 396 if err := s.sendNextBlock(); err != nil { 397 t.Fatalf("failed to broadcast next block: %v", err) 398 } 399 } 400 401 // TestOldAnnounce tests the announcement mechanism with an old block. 402 func (s *Suite) TestOldAnnounce(t *utesting.T) { 403 if err := s.oldAnnounce(); err != nil { 404 t.Fatal(err) 405 } 406 } 407 408 // TestBlockHashAnnounce sends a new block hash announcement and expects 409 // the node to perform a `GetBlockHeaders` request. 410 func (s *Suite) TestBlockHashAnnounce(t *utesting.T) { 411 if err := s.hashAnnounce(); err != nil { 412 t.Fatalf("block hash announcement failed: %v", err) 413 } 414 } 415 416 // TestMaliciousHandshake tries to send malicious data during the handshake. 417 func (s *Suite) TestMaliciousHandshake(t *utesting.T) { 418 if err := s.maliciousHandshakes(t); err != nil { 419 t.Fatal(err) 420 } 421 } 422 423 // TestMaliciousStatus sends a status package with a large total difficulty. 424 func (s *Suite) TestMaliciousStatus(t *utesting.T) { 425 conn, err := s.dial() 426 if err != nil { 427 t.Fatalf("dial failed: %v", err) 428 } 429 defer conn.Close() 430 431 if err := s.maliciousStatus(conn); err != nil { 432 t.Fatal(err) 433 } 434 } 435 436 // TestTransaction sends a valid transaction to the node and 437 // checks if the transaction gets propagated. 438 func (s *Suite) TestTransaction(t *utesting.T) { 439 if err := s.sendSuccessfulTxs(t); err != nil { 440 t.Fatal(err) 441 } 442 } 443 444 // TestMaliciousTx sends several invalid transactions and tests whether 445 // the node will propagate them. 446 func (s *Suite) TestMaliciousTx(t *utesting.T) { 447 if err := s.sendMaliciousTxs(t); err != nil { 448 t.Fatal(err) 449 } 450 } 451 452 // TestLargeTxRequest tests whether a node can fulfill a large GetPooledTransactions 453 // request. 454 func (s *Suite) TestLargeTxRequest(t *utesting.T) { 455 // send the next block to ensure the node is no longer syncing and 456 // is able to accept txs 457 if err := s.sendNextBlock(); err != nil { 458 t.Fatalf("failed to send next block: %v", err) 459 } 460 // send 2000 transactions to the node 461 hashMap, txs, err := generateTxs(s, 2000) 462 if err != nil { 463 t.Fatalf("failed to generate transactions: %v", err) 464 } 465 if err = sendMultipleSuccessfulTxs(t, s, txs); err != nil { 466 t.Fatalf("failed to send multiple txs: %v", err) 467 } 468 // set up connection to receive to ensure node is peered with the receiving connection 469 // before tx request is sent 470 conn, err := s.dial() 471 if err != nil { 472 t.Fatalf("dial failed: %v", err) 473 } 474 defer conn.Close() 475 if err = conn.peer(s.chain, nil); err != nil { 476 t.Fatalf("peering failed: %v", err) 477 } 478 // create and send pooled tx request 479 hashes := make([]common.Hash, 0) 480 for _, hash := range hashMap { 481 hashes = append(hashes, hash) 482 } 483 getTxReq := &GetPooledTransactions{ 484 RequestId: 1234, 485 GetPooledTransactionsPacket: hashes, 486 } 487 if err = conn.Write(getTxReq); err != nil { 488 t.Fatalf("could not write to conn: %v", err) 489 } 490 // check that all received transactions match those that were sent to node 491 switch msg := conn.waitForResponse(s.chain, timeout, getTxReq.RequestId).(type) { 492 case *PooledTransactions: 493 for _, gotTx := range msg.PooledTransactionsPacket { 494 if _, exists := hashMap[gotTx.Hash()]; !exists { 495 t.Fatalf("unexpected tx received: %v", gotTx.Hash()) 496 } 497 } 498 default: 499 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 500 } 501 } 502 503 // TestNewPooledTxs tests whether a node will do a GetPooledTransactions 504 // request upon receiving a NewPooledTransactionHashes announcement. 505 func (s *Suite) TestNewPooledTxs(t *utesting.T) { 506 // send the next block to ensure the node is no longer syncing and 507 // is able to accept txs 508 if err := s.sendNextBlock(); err != nil { 509 t.Fatalf("failed to send next block: %v", err) 510 } 511 512 // generate 50 txs 513 _, txs, err := generateTxs(s, 50) 514 if err != nil { 515 t.Fatalf("failed to generate transactions: %v", err) 516 } 517 hashes := make([]common.Hash, len(txs)) 518 types := make([]byte, len(txs)) 519 sizes := make([]uint32, len(txs)) 520 for i, tx := range txs { 521 hashes[i] = tx.Hash() 522 types[i] = tx.Type() 523 sizes[i] = uint32(tx.Size()) 524 } 525 526 // send announcement 527 conn, err := s.dial() 528 if err != nil { 529 t.Fatalf("dial failed: %v", err) 530 } 531 defer conn.Close() 532 if err = conn.peer(s.chain, nil); err != nil { 533 t.Fatalf("peering failed: %v", err) 534 } 535 536 var ann Message = NewPooledTransactionHashes{Types: types, Sizes: sizes, Hashes: hashes} 537 if conn.negotiatedProtoVersion < zond.ETH68 { 538 ann = NewPooledTransactionHashes66(hashes) 539 } 540 err = conn.Write(ann) 541 if err != nil { 542 t.Fatalf("failed to write to connection: %v", err) 543 } 544 545 // wait for GetPooledTxs request 546 for { 547 msg := conn.readAndServe(s.chain, timeout) 548 switch msg := msg.(type) { 549 case *GetPooledTransactions: 550 if len(msg.GetPooledTransactionsPacket) != len(hashes) { 551 t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsPacket)) 552 } 553 return 554 555 // ignore propagated txs from previous tests 556 case *NewPooledTransactionHashes66: 557 continue 558 case *NewPooledTransactionHashes: 559 continue 560 case *Transactions: 561 continue 562 563 // ignore block announcements from previous tests 564 case *NewBlockHashes: 565 continue 566 case *NewBlock: 567 continue 568 default: 569 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 570 } 571 } 572 }