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