github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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 "crypto/rand" 21 "math/big" 22 "reflect" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/consensus/misc/eip4844" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/crypto/kzg4844" 29 "github.com/ethereum/go-ethereum/eth/protocols/eth" 30 "github.com/ethereum/go-ethereum/internal/utesting" 31 "github.com/ethereum/go-ethereum/p2p" 32 "github.com/ethereum/go-ethereum/p2p/enode" 33 "github.com/holiman/uint256" 34 ) 35 36 // Suite represents a structure used to test a node's conformance 37 // to the eth protocol. 38 type Suite struct { 39 Dest *enode.Node 40 chain *Chain 41 engine *EngineClient 42 } 43 44 // NewSuite creates and returns a new eth-test suite that can 45 // be used to test the given node against the given blockchain 46 // data. 47 func NewSuite(dest *enode.Node, chainDir, engineURL, jwt string) (*Suite, error) { 48 chain, err := NewChain(chainDir) 49 if err != nil { 50 return nil, err 51 } 52 engine, err := NewEngineClient(chainDir, engineURL, jwt) 53 if err != nil { 54 return nil, err 55 } 56 57 return &Suite{ 58 Dest: dest, 59 chain: chain, 60 engine: engine, 61 }, nil 62 } 63 64 func (s *Suite) EthTests() []utesting.Test { 65 return []utesting.Test{ 66 // status 67 {Name: "Status", Fn: s.TestStatus}, 68 // get block headers 69 {Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders}, 70 {Name: "SimultaneousRequests", Fn: s.TestSimultaneousRequests}, 71 {Name: "SameRequestID", Fn: s.TestSameRequestID}, 72 {Name: "ZeroRequestID", Fn: s.TestZeroRequestID}, 73 // get block bodies 74 {Name: "GetBlockBodies", Fn: s.TestGetBlockBodies}, 75 // // malicious handshakes + status 76 {Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake}, 77 {Name: "MaliciousStatus", Fn: s.TestMaliciousStatus}, 78 // test transactions 79 {Name: "LargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true}, 80 {Name: "Transaction", Fn: s.TestTransaction}, 81 {Name: "InvalidTxs", Fn: s.TestInvalidTxs}, 82 {Name: "NewPooledTxs", Fn: s.TestNewPooledTxs}, 83 {Name: "BlobViolations", Fn: s.TestBlobViolations}, 84 } 85 } 86 87 func (s *Suite) SnapTests() []utesting.Test { 88 return []utesting.Test{ 89 {Name: "Status", Fn: s.TestSnapStatus}, 90 {Name: "AccountRange", Fn: s.TestSnapGetAccountRange}, 91 {Name: "GetByteCodes", Fn: s.TestSnapGetByteCodes}, 92 {Name: "GetTrieNodes", Fn: s.TestSnapTrieNodes}, 93 {Name: "GetStorageRanges", Fn: s.TestSnapGetStorageRanges}, 94 } 95 } 96 97 func (s *Suite) TestStatus(t *utesting.T) { 98 t.Log(`This test is just a sanity check. It performs an eth protocol handshake.`) 99 100 conn, err := s.dial() 101 if err != nil { 102 t.Fatalf("dial failed: %v", err) 103 } 104 defer conn.Close() 105 if err := conn.peer(s.chain, nil); err != nil { 106 t.Fatalf("peering failed: %v", err) 107 } 108 } 109 110 // headersMatch returns whether the received headers match the given request 111 func headersMatch(expected []*types.Header, headers []*types.Header) bool { 112 return reflect.DeepEqual(expected, headers) 113 } 114 115 func (s *Suite) TestGetBlockHeaders(t *utesting.T) { 116 t.Log(`This test requests block headers from the node.`) 117 118 conn, err := s.dial() 119 if err != nil { 120 t.Fatalf("dial failed: %v", err) 121 } 122 defer conn.Close() 123 if err = conn.peer(s.chain, nil); err != nil { 124 t.Fatalf("peering failed: %v", err) 125 } 126 // Send headers request. 127 req := ð.GetBlockHeadersPacket{ 128 RequestId: 33, 129 GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ 130 Origin: eth.HashOrNumber{Hash: s.chain.blocks[1].Hash()}, 131 Amount: 2, 132 Skip: 1, 133 Reverse: false, 134 }, 135 } 136 // Read headers response. 137 if err := conn.Write(ethProto, eth.GetBlockHeadersMsg, req); err != nil { 138 t.Fatalf("could not write to connection: %v", err) 139 } 140 headers := new(eth.BlockHeadersPacket) 141 if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers); err != nil { 142 t.Fatalf("error reading msg: %v", err) 143 } 144 if got, want := headers.RequestId, req.RequestId; got != want { 145 t.Fatalf("unexpected request id") 146 } 147 // Check for correct headers. 148 expected, err := s.chain.GetHeaders(req) 149 if err != nil { 150 t.Fatalf("failed to get headers for given request: %v", err) 151 } 152 if !headersMatch(expected, headers.BlockHeadersRequest) { 153 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers) 154 } 155 } 156 157 func (s *Suite) TestSimultaneousRequests(t *utesting.T) { 158 t.Log(`This test requests blocks headers from the node, performing two requests 159 concurrently, with different request IDs.`) 160 161 conn, err := s.dial() 162 if err != nil { 163 t.Fatalf("dial failed: %v", err) 164 } 165 defer conn.Close() 166 if err := conn.peer(s.chain, nil); err != nil { 167 t.Fatalf("peering failed: %v", err) 168 } 169 170 // Create two different requests. 171 req1 := ð.GetBlockHeadersPacket{ 172 RequestId: uint64(111), 173 GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ 174 Origin: eth.HashOrNumber{ 175 Hash: s.chain.blocks[1].Hash(), 176 }, 177 Amount: 2, 178 Skip: 1, 179 Reverse: false, 180 }, 181 } 182 req2 := ð.GetBlockHeadersPacket{ 183 RequestId: uint64(222), 184 GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ 185 Origin: eth.HashOrNumber{ 186 Hash: s.chain.blocks[1].Hash(), 187 }, 188 Amount: 4, 189 Skip: 1, 190 Reverse: false, 191 }, 192 } 193 194 // Send both requests. 195 if err := conn.Write(ethProto, eth.GetBlockHeadersMsg, req1); err != nil { 196 t.Fatalf("failed to write to connection: %v", err) 197 } 198 if err := conn.Write(ethProto, eth.GetBlockHeadersMsg, req2); err != nil { 199 t.Fatalf("failed to write to connection: %v", err) 200 } 201 202 // Wait for responses. 203 headers1 := new(eth.BlockHeadersPacket) 204 if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers1); err != nil { 205 t.Fatalf("error reading block headers msg: %v", err) 206 } 207 if got, want := headers1.RequestId, req1.RequestId; got != want { 208 t.Fatalf("unexpected request id in response: got %d, want %d", got, want) 209 } 210 headers2 := new(eth.BlockHeadersPacket) 211 if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers2); err != nil { 212 t.Fatalf("error reading block headers msg: %v", err) 213 } 214 if got, want := headers2.RequestId, req2.RequestId; got != want { 215 t.Fatalf("unexpected request id in response: got %d, want %d", got, want) 216 } 217 218 // Check received headers for accuracy. 219 if expected, err := s.chain.GetHeaders(req1); err != nil { 220 t.Fatalf("failed to get expected headers for request 1: %v", err) 221 } else if !headersMatch(expected, headers1.BlockHeadersRequest) { 222 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers1) 223 } 224 if expected, err := s.chain.GetHeaders(req2); err != nil { 225 t.Fatalf("failed to get expected headers for request 2: %v", err) 226 } else if !headersMatch(expected, headers2.BlockHeadersRequest) { 227 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers2) 228 } 229 } 230 231 func (s *Suite) TestSameRequestID(t *utesting.T) { 232 t.Log(`This test requests block headers, performing two concurrent requests with the 233 same request ID. The node should handle the request by responding to both requests.`) 234 235 conn, err := s.dial() 236 if err != nil { 237 t.Fatalf("dial failed: %v", err) 238 } 239 defer conn.Close() 240 if err := conn.peer(s.chain, nil); err != nil { 241 t.Fatalf("peering failed: %v", err) 242 } 243 244 // Create two different requests with the same ID. 245 reqID := uint64(1234) 246 request1 := ð.GetBlockHeadersPacket{ 247 RequestId: reqID, 248 GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ 249 Origin: eth.HashOrNumber{ 250 Number: 1, 251 }, 252 Amount: 2, 253 }, 254 } 255 request2 := ð.GetBlockHeadersPacket{ 256 RequestId: reqID, 257 GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ 258 Origin: eth.HashOrNumber{ 259 Number: 33, 260 }, 261 Amount: 2, 262 }, 263 } 264 265 // Send the requests. 266 if err = conn.Write(ethProto, eth.GetBlockHeadersMsg, request1); err != nil { 267 t.Fatalf("failed to write to connection: %v", err) 268 } 269 if err = conn.Write(ethProto, eth.GetBlockHeadersMsg, request2); err != nil { 270 t.Fatalf("failed to write to connection: %v", err) 271 } 272 273 // Wait for the responses. 274 headers1 := new(eth.BlockHeadersPacket) 275 if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers1); err != nil { 276 t.Fatalf("error reading from connection: %v", err) 277 } 278 if got, want := headers1.RequestId, request1.RequestId; got != want { 279 t.Fatalf("unexpected request id: got %d, want %d", got, want) 280 } 281 headers2 := new(eth.BlockHeadersPacket) 282 if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers2); err != nil { 283 t.Fatalf("error reading from connection: %v", err) 284 } 285 if got, want := headers2.RequestId, request2.RequestId; got != want { 286 t.Fatalf("unexpected request id: got %d, want %d", got, want) 287 } 288 289 // Check if headers match. 290 if expected, err := s.chain.GetHeaders(request1); err != nil { 291 t.Fatalf("failed to get expected block headers: %v", err) 292 } else if !headersMatch(expected, headers1.BlockHeadersRequest) { 293 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers1) 294 } 295 if expected, err := s.chain.GetHeaders(request2); err != nil { 296 t.Fatalf("failed to get expected block headers: %v", err) 297 } else if !headersMatch(expected, headers2.BlockHeadersRequest) { 298 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers2) 299 } 300 } 301 302 func (s *Suite) TestZeroRequestID(t *utesting.T) { 303 t.Log(`This test sends a GetBlockHeaders message with a request-id of zero, 304 and expects a response.`) 305 306 conn, err := s.dial() 307 if err != nil { 308 t.Fatalf("dial failed: %v", err) 309 } 310 defer conn.Close() 311 if err := conn.peer(s.chain, nil); err != nil { 312 t.Fatalf("peering failed: %v", err) 313 } 314 req := ð.GetBlockHeadersPacket{ 315 GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ 316 Origin: eth.HashOrNumber{Number: 0}, 317 Amount: 2, 318 }, 319 } 320 // Read headers response. 321 if err := conn.Write(ethProto, eth.GetBlockHeadersMsg, req); err != nil { 322 t.Fatalf("could not write to connection: %v", err) 323 } 324 headers := new(eth.BlockHeadersPacket) 325 if err := conn.ReadMsg(ethProto, eth.BlockHeadersMsg, &headers); err != nil { 326 t.Fatalf("error reading msg: %v", err) 327 } 328 if got, want := headers.RequestId, req.RequestId; got != want { 329 t.Fatalf("unexpected request id") 330 } 331 if expected, err := s.chain.GetHeaders(req); err != nil { 332 t.Fatalf("failed to get expected block headers: %v", err) 333 } else if !headersMatch(expected, headers.BlockHeadersRequest) { 334 t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers) 335 } 336 } 337 338 func (s *Suite) TestGetBlockBodies(t *utesting.T) { 339 t.Log(`This test sends GetBlockBodies requests to the node for known blocks in the test chain.`) 340 341 conn, err := s.dial() 342 if err != nil { 343 t.Fatalf("dial failed: %v", err) 344 } 345 defer conn.Close() 346 if err := conn.peer(s.chain, nil); err != nil { 347 t.Fatalf("peering failed: %v", err) 348 } 349 // Create block bodies request. 350 req := ð.GetBlockBodiesPacket{ 351 RequestId: 55, 352 GetBlockBodiesRequest: eth.GetBlockBodiesRequest{ 353 s.chain.blocks[54].Hash(), 354 s.chain.blocks[75].Hash(), 355 }, 356 } 357 if err := conn.Write(ethProto, eth.GetBlockBodiesMsg, req); err != nil { 358 t.Fatalf("could not write to connection: %v", err) 359 } 360 // Wait for response. 361 resp := new(eth.BlockBodiesPacket) 362 if err := conn.ReadMsg(ethProto, eth.BlockBodiesMsg, &resp); err != nil { 363 t.Fatalf("error reading block bodies msg: %v", err) 364 } 365 if got, want := resp.RequestId, req.RequestId; got != want { 366 t.Fatalf("unexpected request id in respond", got, want) 367 } 368 bodies := resp.BlockBodiesResponse 369 if len(bodies) != len(req.GetBlockBodiesRequest) { 370 t.Fatalf("wrong bodies in response: expected %d bodies, got %d", len(req.GetBlockBodiesRequest), len(bodies)) 371 } 372 } 373 374 // randBuf makes a random buffer size kilobytes large. 375 func randBuf(size int) []byte { 376 buf := make([]byte, size*1024) 377 rand.Read(buf) 378 return buf 379 } 380 381 func (s *Suite) TestMaliciousHandshake(t *utesting.T) { 382 t.Log(`This test tries to send malicious data during the devp2p handshake, in various ways.`) 383 384 // Write hello to client. 385 var ( 386 key, _ = crypto.GenerateKey() 387 pub0 = crypto.FromECDSAPub(&key.PublicKey)[1:] 388 version = eth.ProtocolVersions[0] 389 ) 390 handshakes := []*protoHandshake{ 391 { 392 Version: 5, 393 Caps: []p2p.Cap{ 394 {Name: string(randBuf(2)), Version: version}, 395 }, 396 ID: pub0, 397 }, 398 { 399 Version: 5, 400 Caps: []p2p.Cap{ 401 {Name: "eth", Version: version}, 402 }, 403 ID: append(pub0, byte(0)), 404 }, 405 { 406 Version: 5, 407 Caps: []p2p.Cap{ 408 {Name: "eth", Version: version}, 409 }, 410 ID: append(pub0, pub0...), 411 }, 412 { 413 Version: 5, 414 Caps: []p2p.Cap{ 415 {Name: "eth", Version: version}, 416 }, 417 ID: randBuf(2), 418 }, 419 { 420 Version: 5, 421 Caps: []p2p.Cap{ 422 {Name: string(randBuf(2)), Version: version}, 423 }, 424 ID: randBuf(2), 425 }, 426 } 427 for _, handshake := range handshakes { 428 conn, err := s.dialAs(key) 429 if err != nil { 430 t.Fatalf("dial failed: %v", err) 431 } 432 defer conn.Close() 433 434 if err := conn.Write(ethProto, handshakeMsg, handshake); err != nil { 435 t.Fatalf("could not write to connection: %v", err) 436 } 437 // Check that the peer disconnected 438 for i := 0; i < 2; i++ { 439 code, _, err := conn.Read() 440 if err != nil { 441 // Client may have disconnected without sending disconnect msg. 442 continue 443 } 444 switch code { 445 case discMsg: 446 case handshakeMsg: 447 // Discard one hello as Hello's are sent concurrently 448 continue 449 default: 450 t.Fatalf("unexpected msg: code %d", code) 451 } 452 } 453 } 454 } 455 456 func (s *Suite) TestMaliciousStatus(t *utesting.T) { 457 t.Log(`This test sends a malicious eth Status message to the node and expects a disconnect.`) 458 459 conn, err := s.dial() 460 if err != nil { 461 t.Fatalf("dial failed: %v", err) 462 } 463 defer conn.Close() 464 if err := conn.handshake(); err != nil { 465 t.Fatalf("handshake failed: %v", err) 466 } 467 // Create status with large total difficulty. 468 status := ð.StatusPacket{ 469 ProtocolVersion: uint32(conn.negotiatedProtoVersion), 470 NetworkID: s.chain.config.ChainID.Uint64(), 471 TD: new(big.Int).SetBytes(randBuf(2048)), 472 Head: s.chain.Head().Hash(), 473 Genesis: s.chain.GetBlock(0).Hash(), 474 ForkID: s.chain.ForkID(), 475 } 476 if err := conn.statusExchange(s.chain, status); err != nil { 477 t.Fatalf("status exchange failed: %v", err) 478 } 479 // Wait for disconnect. 480 code, _, err := conn.Read() 481 if err != nil { 482 t.Fatalf("error reading from connection: %v", err) 483 } 484 switch code { 485 case discMsg: 486 break 487 default: 488 t.Fatalf("expected disconnect, got: %d", code) 489 } 490 } 491 492 func (s *Suite) TestTransaction(t *utesting.T) { 493 t.Log(`This test sends a valid transaction to the node and checks if the 494 transaction gets propagated.`) 495 496 // Nudge client out of syncing mode to accept pending txs. 497 if err := s.engine.sendForkchoiceUpdated(); err != nil { 498 t.Fatalf("failed to send next block: %v", err) 499 } 500 from, nonce := s.chain.GetSender(0) 501 inner := &types.DynamicFeeTx{ 502 ChainID: s.chain.config.ChainID, 503 Nonce: nonce, 504 GasTipCap: common.Big1, 505 GasFeeCap: s.chain.Head().BaseFee(), 506 Gas: 30000, 507 To: &common.Address{0xaa}, 508 Value: common.Big1, 509 } 510 tx, err := s.chain.SignTx(from, types.NewTx(inner)) 511 if err != nil { 512 t.Fatalf("failed to sign tx: %v", err) 513 } 514 if err := s.sendTxs(t, []*types.Transaction{tx}); err != nil { 515 t.Fatal(err) 516 } 517 s.chain.IncNonce(from, 1) 518 } 519 520 func (s *Suite) TestInvalidTxs(t *utesting.T) { 521 t.Log(`This test sends several kinds of invalid transactions and checks that the node 522 does not propagate them.`) 523 524 // Nudge client out of syncing mode to accept pending txs. 525 if err := s.engine.sendForkchoiceUpdated(); err != nil { 526 t.Fatalf("failed to send next block: %v", err) 527 } 528 529 from, nonce := s.chain.GetSender(0) 530 inner := &types.DynamicFeeTx{ 531 ChainID: s.chain.config.ChainID, 532 Nonce: nonce, 533 GasTipCap: common.Big1, 534 GasFeeCap: s.chain.Head().BaseFee(), 535 Gas: 30000, 536 To: &common.Address{0xaa}, 537 } 538 tx, err := s.chain.SignTx(from, types.NewTx(inner)) 539 if err != nil { 540 t.Fatalf("failed to sign tx: %v", err) 541 } 542 if err := s.sendTxs(t, []*types.Transaction{tx}); err != nil { 543 t.Fatalf("failed to send txs: %v", err) 544 } 545 s.chain.IncNonce(from, 1) 546 547 inners := []*types.DynamicFeeTx{ 548 // Nonce already used 549 { 550 ChainID: s.chain.config.ChainID, 551 Nonce: nonce - 1, 552 GasTipCap: common.Big1, 553 GasFeeCap: s.chain.Head().BaseFee(), 554 Gas: 100000, 555 }, 556 // Value exceeds balance 557 { 558 Nonce: nonce, 559 GasTipCap: common.Big1, 560 GasFeeCap: s.chain.Head().BaseFee(), 561 Gas: 100000, 562 Value: s.chain.Balance(from), 563 }, 564 // Gas limit too low 565 { 566 Nonce: nonce, 567 GasTipCap: common.Big1, 568 GasFeeCap: s.chain.Head().BaseFee(), 569 Gas: 1337, 570 }, 571 // Code size too large 572 { 573 Nonce: nonce, 574 GasTipCap: common.Big1, 575 GasFeeCap: s.chain.Head().BaseFee(), 576 Data: randBuf(50), 577 Gas: 1_000_000, 578 }, 579 // Data too large 580 { 581 Nonce: nonce, 582 GasTipCap: common.Big1, 583 GasFeeCap: s.chain.Head().BaseFee(), 584 To: &common.Address{0xaa}, 585 Data: randBuf(128), 586 Gas: 5_000_000, 587 }, 588 } 589 590 var txs []*types.Transaction 591 for _, inner := range inners { 592 tx, err := s.chain.SignTx(from, types.NewTx(inner)) 593 if err != nil { 594 t.Fatalf("failed to sign tx: %v", err) 595 } 596 txs = append(txs, tx) 597 } 598 if err := s.sendInvalidTxs(t, txs); err != nil { 599 t.Fatalf("failed to send invalid txs: %v", err) 600 } 601 } 602 603 func (s *Suite) TestLargeTxRequest(t *utesting.T) { 604 t.Log(`This test first send ~2000 transactions to the node, then requests them 605 on another peer connection using GetPooledTransactions.`) 606 607 // Nudge client out of syncing mode to accept pending txs. 608 if err := s.engine.sendForkchoiceUpdated(); err != nil { 609 t.Fatalf("failed to send next block: %v", err) 610 } 611 612 // Generate many transactions to seed target with. 613 var ( 614 from, nonce = s.chain.GetSender(1) 615 count = 2000 616 txs []*types.Transaction 617 hashes []common.Hash 618 set = make(map[common.Hash]struct{}) 619 ) 620 for i := 0; i < count; i++ { 621 inner := &types.DynamicFeeTx{ 622 ChainID: s.chain.config.ChainID, 623 Nonce: nonce + uint64(i), 624 GasTipCap: common.Big1, 625 GasFeeCap: s.chain.Head().BaseFee(), 626 Gas: 75000, 627 } 628 tx, err := s.chain.SignTx(from, types.NewTx(inner)) 629 if err != nil { 630 t.Fatalf("failed to sign tx: err") 631 } 632 txs = append(txs, tx) 633 set[tx.Hash()] = struct{}{} 634 hashes = append(hashes, tx.Hash()) 635 } 636 s.chain.IncNonce(from, uint64(count)) 637 638 // Send txs. 639 if err := s.sendTxs(t, txs); err != nil { 640 t.Fatalf("failed to send txs: %v", err) 641 } 642 643 // Set up receive connection to ensure node is peered with the receiving 644 // connection before tx request is sent. 645 conn, err := s.dial() 646 if err != nil { 647 t.Fatalf("dial failed: %v", err) 648 } 649 defer conn.Close() 650 if err = conn.peer(s.chain, nil); err != nil { 651 t.Fatalf("peering failed: %v", err) 652 } 653 // Create and send pooled tx request. 654 req := ð.GetPooledTransactionsPacket{ 655 RequestId: 1234, 656 GetPooledTransactionsRequest: hashes, 657 } 658 if err = conn.Write(ethProto, eth.GetPooledTransactionsMsg, req); err != nil { 659 t.Fatalf("could not write to conn: %v", err) 660 } 661 // Check that all received transactions match those that were sent to node. 662 msg := new(eth.PooledTransactionsPacket) 663 if err := conn.ReadMsg(ethProto, eth.PooledTransactionsMsg, &msg); err != nil { 664 t.Fatalf("error reading from connection: %v", err) 665 } 666 if got, want := msg.RequestId, req.RequestId; got != want { 667 t.Fatalf("unexpected request id in response: got %d, want %d", got, want) 668 } 669 for _, got := range msg.PooledTransactionsResponse { 670 if _, exists := set[got.Hash()]; !exists { 671 t.Fatalf("unexpected tx received: %v", got.Hash()) 672 } 673 } 674 } 675 676 func (s *Suite) TestNewPooledTxs(t *utesting.T) { 677 t.Log(`This test announces transaction hashes to the node and expects it to fetch 678 the transactions using a GetPooledTransactions request.`) 679 680 // Nudge client out of syncing mode to accept pending txs. 681 if err := s.engine.sendForkchoiceUpdated(); err != nil { 682 t.Fatalf("failed to send next block: %v", err) 683 } 684 685 var ( 686 count = 50 687 from, nonce = s.chain.GetSender(1) 688 hashes = make([]common.Hash, count) 689 txTypes = make([]byte, count) 690 sizes = make([]uint32, count) 691 ) 692 for i := 0; i < count; i++ { 693 inner := &types.DynamicFeeTx{ 694 ChainID: s.chain.config.ChainID, 695 Nonce: nonce + uint64(i), 696 GasTipCap: common.Big1, 697 GasFeeCap: s.chain.Head().BaseFee(), 698 Gas: 75000, 699 } 700 tx, err := s.chain.SignTx(from, types.NewTx(inner)) 701 if err != nil { 702 t.Fatalf("failed to sign tx: err") 703 } 704 hashes[i] = tx.Hash() 705 txTypes[i] = tx.Type() 706 sizes[i] = uint32(tx.Size()) 707 } 708 s.chain.IncNonce(from, uint64(count)) 709 710 // Connect to peer. 711 conn, err := s.dial() 712 if err != nil { 713 t.Fatalf("dial failed: %v", err) 714 } 715 defer conn.Close() 716 if err = conn.peer(s.chain, nil); err != nil { 717 t.Fatalf("peering failed: %v", err) 718 } 719 720 // Send announcement. 721 ann := eth.NewPooledTransactionHashesPacket{Types: txTypes, Sizes: sizes, Hashes: hashes} 722 err = conn.Write(ethProto, eth.NewPooledTransactionHashesMsg, ann) 723 if err != nil { 724 t.Fatalf("failed to write to connection: %v", err) 725 } 726 727 // Wait for GetPooledTxs request. 728 for { 729 msg, err := conn.ReadEth() 730 if err != nil { 731 t.Fatalf("failed to read eth msg: %v", err) 732 } 733 switch msg := msg.(type) { 734 case *eth.GetPooledTransactionsPacket: 735 if len(msg.GetPooledTransactionsRequest) != len(hashes) { 736 t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsRequest)) 737 } 738 return 739 case *eth.NewPooledTransactionHashesPacket: 740 continue 741 case *eth.TransactionsPacket: 742 continue 743 default: 744 t.Fatalf("unexpected %s", pretty.Sdump(msg)) 745 } 746 } 747 } 748 749 func makeSidecar(data ...byte) *types.BlobTxSidecar { 750 var ( 751 blobs = make([]kzg4844.Blob, len(data)) 752 commitments []kzg4844.Commitment 753 proofs []kzg4844.Proof 754 ) 755 for i := range blobs { 756 blobs[i][0] = data[i] 757 c, _ := kzg4844.BlobToCommitment(&blobs[i]) 758 p, _ := kzg4844.ComputeBlobProof(&blobs[i], c) 759 commitments = append(commitments, c) 760 proofs = append(proofs, p) 761 } 762 return &types.BlobTxSidecar{ 763 Blobs: blobs, 764 Commitments: commitments, 765 Proofs: proofs, 766 } 767 } 768 769 func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Transactions) { 770 from, nonce := s.chain.GetSender(5) 771 for i := 0; i < count; i++ { 772 // Make blob data, max of 2 blobs per tx. 773 blobdata := make([]byte, blobs%3) 774 for i := range blobdata { 775 blobdata[i] = discriminator 776 blobs -= 1 777 } 778 inner := &types.BlobTx{ 779 ChainID: uint256.MustFromBig(s.chain.config.ChainID), 780 Nonce: nonce + uint64(i), 781 GasTipCap: uint256.NewInt(1), 782 GasFeeCap: uint256.MustFromBig(s.chain.Head().BaseFee()), 783 Gas: 100000, 784 BlobFeeCap: uint256.MustFromBig(eip4844.CalcBlobFee(*s.chain.Head().ExcessBlobGas())), 785 BlobHashes: makeSidecar(blobdata...).BlobHashes(), 786 Sidecar: makeSidecar(blobdata...), 787 } 788 tx, err := s.chain.SignTx(from, types.NewTx(inner)) 789 if err != nil { 790 panic("blob tx signing failed") 791 } 792 txs = append(txs, tx) 793 } 794 return txs 795 } 796 797 func (s *Suite) TestBlobViolations(t *utesting.T) { 798 t.Log(`This test sends some invalid blob tx announcements and expects the node to disconnect.`) 799 800 if err := s.engine.sendForkchoiceUpdated(); err != nil { 801 t.Fatalf("send fcu failed: %v", err) 802 } 803 // Create blob txs for each tests with unique tx hashes. 804 var ( 805 t1 = s.makeBlobTxs(2, 3, 0x1) 806 t2 = s.makeBlobTxs(2, 3, 0x2) 807 ) 808 for _, test := range []struct { 809 ann eth.NewPooledTransactionHashesPacket 810 resp eth.PooledTransactionsResponse 811 }{ 812 // Invalid tx size. 813 { 814 ann: eth.NewPooledTransactionHashesPacket{ 815 Types: []byte{types.BlobTxType, types.BlobTxType}, 816 Sizes: []uint32{uint32(t1[0].Size()), uint32(t1[1].Size() + 10)}, 817 Hashes: []common.Hash{t1[0].Hash(), t1[1].Hash()}, 818 }, 819 resp: eth.PooledTransactionsResponse(t1), 820 }, 821 // Wrong tx type. 822 { 823 ann: eth.NewPooledTransactionHashesPacket{ 824 Types: []byte{types.DynamicFeeTxType, types.BlobTxType}, 825 Sizes: []uint32{uint32(t2[0].Size()), uint32(t2[1].Size())}, 826 Hashes: []common.Hash{t2[0].Hash(), t2[1].Hash()}, 827 }, 828 resp: eth.PooledTransactionsResponse(t2), 829 }, 830 } { 831 conn, err := s.dial() 832 if err != nil { 833 t.Fatalf("dial fail: %v", err) 834 } 835 if err := conn.peer(s.chain, nil); err != nil { 836 t.Fatalf("peering failed: %v", err) 837 } 838 if err := conn.Write(ethProto, eth.NewPooledTransactionHashesMsg, test.ann); err != nil { 839 t.Fatalf("sending announcement failed: %v", err) 840 } 841 req := new(eth.GetPooledTransactionsPacket) 842 if err := conn.ReadMsg(ethProto, eth.GetPooledTransactionsMsg, req); err != nil { 843 t.Fatalf("reading pooled tx request failed: %v", err) 844 } 845 resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, PooledTransactionsResponse: test.resp} 846 if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil { 847 t.Fatalf("writing pooled tx response failed: %v", err) 848 } 849 if code, _, err := conn.Read(); err != nil { 850 t.Fatalf("expected disconnect on blob violation, got err: %v", err) 851 } else if code != discMsg { 852 t.Fatalf("expected disconnect on blob violation, got msg code: %d", code) 853 } 854 conn.Close() 855 } 856 }