github.com/matthieu/go-ethereum@v1.13.2/eth/protocol_test.go (about) 1 // Copyright 2014 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 eth 18 19 import ( 20 "fmt" 21 "math/big" 22 "sync" 23 "sync/atomic" 24 "testing" 25 "time" 26 27 "github.com/matthieu/go-ethereum/common" 28 "github.com/matthieu/go-ethereum/consensus/ethash" 29 "github.com/matthieu/go-ethereum/core" 30 "github.com/matthieu/go-ethereum/core/forkid" 31 "github.com/matthieu/go-ethereum/core/rawdb" 32 "github.com/matthieu/go-ethereum/core/types" 33 "github.com/matthieu/go-ethereum/core/vm" 34 "github.com/matthieu/go-ethereum/crypto" 35 "github.com/matthieu/go-ethereum/eth/downloader" 36 "github.com/matthieu/go-ethereum/event" 37 "github.com/matthieu/go-ethereum/p2p" 38 "github.com/matthieu/go-ethereum/p2p/enode" 39 "github.com/matthieu/go-ethereum/params" 40 "github.com/matthieu/go-ethereum/rlp" 41 ) 42 43 func init() { 44 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 45 } 46 47 var testAccount, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 48 49 // Tests that handshake failures are detected and reported correctly. 50 func TestStatusMsgErrors63(t *testing.T) { 51 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 52 var ( 53 genesis = pm.blockchain.Genesis() 54 head = pm.blockchain.CurrentHeader() 55 td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 56 ) 57 defer pm.Stop() 58 59 tests := []struct { 60 code uint64 61 data interface{} 62 wantError error 63 }{ 64 { 65 code: TransactionMsg, data: []interface{}{}, 66 wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"), 67 }, 68 { 69 code: StatusMsg, data: statusData63{10, DefaultConfig.NetworkId, td, head.Hash(), genesis.Hash()}, 70 wantError: errResp(ErrProtocolVersionMismatch, "10 (!= %d)", 63), 71 }, 72 { 73 code: StatusMsg, data: statusData63{63, 999, td, head.Hash(), genesis.Hash()}, 74 wantError: errResp(ErrNetworkIDMismatch, "999 (!= %d)", DefaultConfig.NetworkId), 75 }, 76 { 77 code: StatusMsg, data: statusData63{63, DefaultConfig.NetworkId, td, head.Hash(), common.Hash{3}}, 78 wantError: errResp(ErrGenesisMismatch, "0300000000000000 (!= %x)", genesis.Hash().Bytes()[:8]), 79 }, 80 } 81 for i, test := range tests { 82 p, errc := newTestPeer("peer", 63, pm, false) 83 // The send call might hang until reset because 84 // the protocol might not read the payload. 85 go p2p.Send(p.app, test.code, test.data) 86 87 select { 88 case err := <-errc: 89 if err == nil { 90 t.Errorf("test %d: protocol returned nil error, want %q", i, test.wantError) 91 } else if err.Error() != test.wantError.Error() { 92 t.Errorf("test %d: wrong error: got %q, want %q", i, err, test.wantError) 93 } 94 case <-time.After(2 * time.Second): 95 t.Errorf("protocol did not shut down within 2 seconds") 96 } 97 p.close() 98 } 99 } 100 101 func TestStatusMsgErrors64(t *testing.T) { 102 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 103 var ( 104 genesis = pm.blockchain.Genesis() 105 head = pm.blockchain.CurrentHeader() 106 td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 107 forkID = forkid.NewID(pm.blockchain) 108 ) 109 defer pm.Stop() 110 111 tests := []struct { 112 code uint64 113 data interface{} 114 wantError error 115 }{ 116 { 117 code: TransactionMsg, data: []interface{}{}, 118 wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"), 119 }, 120 { 121 code: StatusMsg, data: statusData{10, DefaultConfig.NetworkId, td, head.Hash(), genesis.Hash(), forkID}, 122 wantError: errResp(ErrProtocolVersionMismatch, "10 (!= %d)", 64), 123 }, 124 { 125 code: StatusMsg, data: statusData{64, 999, td, head.Hash(), genesis.Hash(), forkID}, 126 wantError: errResp(ErrNetworkIDMismatch, "999 (!= %d)", DefaultConfig.NetworkId), 127 }, 128 { 129 code: StatusMsg, data: statusData{64, DefaultConfig.NetworkId, td, head.Hash(), common.Hash{3}, forkID}, 130 wantError: errResp(ErrGenesisMismatch, "0300000000000000000000000000000000000000000000000000000000000000 (!= %x)", genesis.Hash()), 131 }, 132 { 133 code: StatusMsg, data: statusData{64, DefaultConfig.NetworkId, td, head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}}, 134 wantError: errResp(ErrForkIDRejected, forkid.ErrLocalIncompatibleOrStale.Error()), 135 }, 136 } 137 for i, test := range tests { 138 p, errc := newTestPeer("peer", 64, pm, false) 139 // The send call might hang until reset because 140 // the protocol might not read the payload. 141 go p2p.Send(p.app, test.code, test.data) 142 143 select { 144 case err := <-errc: 145 if err == nil { 146 t.Errorf("test %d: protocol returned nil error, want %q", i, test.wantError) 147 } else if err.Error() != test.wantError.Error() { 148 t.Errorf("test %d: wrong error: got %q, want %q", i, err, test.wantError) 149 } 150 case <-time.After(2 * time.Second): 151 t.Errorf("protocol did not shut down within 2 seconds") 152 } 153 p.close() 154 } 155 } 156 157 func TestForkIDSplit(t *testing.T) { 158 var ( 159 engine = ethash.NewFaker() 160 161 configNoFork = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)} 162 configProFork = ¶ms.ChainConfig{ 163 HomesteadBlock: big.NewInt(1), 164 EIP150Block: big.NewInt(2), 165 EIP155Block: big.NewInt(2), 166 EIP158Block: big.NewInt(2), 167 ByzantiumBlock: big.NewInt(3), 168 } 169 dbNoFork = rawdb.NewMemoryDatabase() 170 dbProFork = rawdb.NewMemoryDatabase() 171 172 gspecNoFork = &core.Genesis{Config: configNoFork} 173 gspecProFork = &core.Genesis{Config: configProFork} 174 175 genesisNoFork = gspecNoFork.MustCommit(dbNoFork) 176 genesisProFork = gspecProFork.MustCommit(dbProFork) 177 178 chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil) 179 chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil) 180 181 blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil) 182 blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil) 183 184 ethNoFork, _ = NewProtocolManager(configNoFork, nil, downloader.FullSync, 1, new(event.TypeMux), &testTxPool{pool: make(map[common.Hash]*types.Transaction)}, engine, chainNoFork, dbNoFork, 1, nil) 185 ethProFork, _ = NewProtocolManager(configProFork, nil, downloader.FullSync, 1, new(event.TypeMux), &testTxPool{pool: make(map[common.Hash]*types.Transaction)}, engine, chainProFork, dbProFork, 1, nil) 186 ) 187 ethNoFork.Start(1000) 188 ethProFork.Start(1000) 189 190 // Both nodes should allow the other to connect (same genesis, next fork is the same) 191 p2pNoFork, p2pProFork := p2p.MsgPipe() 192 peerNoFork := newPeer(64, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 193 peerProFork := newPeer(64, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 194 195 errc := make(chan error, 2) 196 go func() { errc <- ethNoFork.handle(peerProFork) }() 197 go func() { errc <- ethProFork.handle(peerNoFork) }() 198 199 select { 200 case err := <-errc: 201 t.Fatalf("frontier nofork <-> profork failed: %v", err) 202 case <-time.After(250 * time.Millisecond): 203 p2pNoFork.Close() 204 p2pProFork.Close() 205 } 206 // Progress into Homestead. Fork's match, so we don't care what the future holds 207 chainNoFork.InsertChain(blocksNoFork[:1]) 208 chainProFork.InsertChain(blocksProFork[:1]) 209 210 p2pNoFork, p2pProFork = p2p.MsgPipe() 211 peerNoFork = newPeer(64, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 212 peerProFork = newPeer(64, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 213 214 errc = make(chan error, 2) 215 go func() { errc <- ethNoFork.handle(peerProFork) }() 216 go func() { errc <- ethProFork.handle(peerNoFork) }() 217 218 select { 219 case err := <-errc: 220 t.Fatalf("homestead nofork <-> profork failed: %v", err) 221 case <-time.After(250 * time.Millisecond): 222 p2pNoFork.Close() 223 p2pProFork.Close() 224 } 225 // Progress into Spurious. Forks mismatch, signalling differing chains, reject 226 chainNoFork.InsertChain(blocksNoFork[1:2]) 227 chainProFork.InsertChain(blocksProFork[1:2]) 228 229 p2pNoFork, p2pProFork = p2p.MsgPipe() 230 peerNoFork = newPeer(64, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 231 peerProFork = newPeer(64, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 232 233 errc = make(chan error, 2) 234 go func() { errc <- ethNoFork.handle(peerProFork) }() 235 go func() { errc <- ethProFork.handle(peerNoFork) }() 236 237 select { 238 case err := <-errc: 239 if want := errResp(ErrForkIDRejected, forkid.ErrLocalIncompatibleOrStale.Error()); err.Error() != want.Error() { 240 t.Fatalf("fork ID rejection error mismatch: have %v, want %v", err, want) 241 } 242 case <-time.After(250 * time.Millisecond): 243 t.Fatalf("split peers not rejected") 244 } 245 } 246 247 // This test checks that received transactions are added to the local pool. 248 func TestRecvTransactions63(t *testing.T) { testRecvTransactions(t, 63) } 249 func TestRecvTransactions64(t *testing.T) { testRecvTransactions(t, 64) } 250 func TestRecvTransactions65(t *testing.T) { testRecvTransactions(t, 65) } 251 252 func testRecvTransactions(t *testing.T, protocol int) { 253 txAdded := make(chan []*types.Transaction) 254 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, txAdded) 255 pm.acceptTxs = 1 // mark synced to accept transactions 256 p, _ := newTestPeer("peer", protocol, pm, true) 257 defer pm.Stop() 258 defer p.close() 259 260 tx := newTestTransaction(testAccount, 0, 0) 261 if err := p2p.Send(p.app, TransactionMsg, []interface{}{tx}); err != nil { 262 t.Fatalf("send error: %v", err) 263 } 264 select { 265 case added := <-txAdded: 266 if len(added) != 1 { 267 t.Errorf("wrong number of added transactions: got %d, want 1", len(added)) 268 } else if added[0].Hash() != tx.Hash() { 269 t.Errorf("added wrong tx hash: got %v, want %v", added[0].Hash(), tx.Hash()) 270 } 271 case <-time.After(2 * time.Second): 272 t.Errorf("no NewTxsEvent received within 2 seconds") 273 } 274 } 275 276 // This test checks that pending transactions are sent. 277 func TestSendTransactions63(t *testing.T) { testSendTransactions(t, 63) } 278 func TestSendTransactions64(t *testing.T) { testSendTransactions(t, 64) } 279 func TestSendTransactions65(t *testing.T) { testSendTransactions(t, 65) } 280 281 func testSendTransactions(t *testing.T, protocol int) { 282 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 283 defer pm.Stop() 284 285 // Fill the pool with big transactions (use a subscription to wait until all 286 // the transactions are announced to avoid spurious events causing extra 287 // broadcasts). 288 const txsize = txsyncPackSize / 10 289 alltxs := make([]*types.Transaction, 100) 290 for nonce := range alltxs { 291 alltxs[nonce] = newTestTransaction(testAccount, uint64(nonce), txsize) 292 } 293 pm.txpool.AddRemotes(alltxs) 294 time.Sleep(100 * time.Millisecond) // Wait until new tx even gets out of the system (lame) 295 296 // Connect several peers. They should all receive the pending transactions. 297 var wg sync.WaitGroup 298 checktxs := func(p *testPeer) { 299 defer wg.Done() 300 defer p.close() 301 seen := make(map[common.Hash]bool) 302 for _, tx := range alltxs { 303 seen[tx.Hash()] = false 304 } 305 for n := 0; n < len(alltxs) && !t.Failed(); { 306 var forAllHashes func(callback func(hash common.Hash)) 307 switch protocol { 308 case 63: 309 fallthrough 310 case 64: 311 msg, err := p.app.ReadMsg() 312 if err != nil { 313 t.Errorf("%v: read error: %v", p.Peer, err) 314 continue 315 } else if msg.Code != TransactionMsg { 316 t.Errorf("%v: got code %d, want TxMsg", p.Peer, msg.Code) 317 continue 318 } 319 var txs []*types.Transaction 320 if err := msg.Decode(&txs); err != nil { 321 t.Errorf("%v: %v", p.Peer, err) 322 continue 323 } 324 forAllHashes = func(callback func(hash common.Hash)) { 325 for _, tx := range txs { 326 callback(tx.Hash()) 327 } 328 } 329 case 65: 330 msg, err := p.app.ReadMsg() 331 if err != nil { 332 t.Errorf("%v: read error: %v", p.Peer, err) 333 continue 334 } else if msg.Code != NewPooledTransactionHashesMsg { 335 t.Errorf("%v: got code %d, want NewPooledTransactionHashesMsg", p.Peer, msg.Code) 336 continue 337 } 338 var hashes []common.Hash 339 if err := msg.Decode(&hashes); err != nil { 340 t.Errorf("%v: %v", p.Peer, err) 341 continue 342 } 343 forAllHashes = func(callback func(hash common.Hash)) { 344 for _, h := range hashes { 345 callback(h) 346 } 347 } 348 } 349 forAllHashes(func(hash common.Hash) { 350 seentx, want := seen[hash] 351 if seentx { 352 t.Errorf("%v: got tx more than once: %x", p.Peer, hash) 353 } 354 if !want { 355 t.Errorf("%v: got unexpected tx: %x", p.Peer, hash) 356 } 357 seen[hash] = true 358 n++ 359 }) 360 } 361 } 362 for i := 0; i < 3; i++ { 363 p, _ := newTestPeer(fmt.Sprintf("peer #%d", i), protocol, pm, true) 364 wg.Add(1) 365 go checktxs(p) 366 } 367 wg.Wait() 368 } 369 370 func TestTransactionPropagation(t *testing.T) { testSyncTransaction(t, true) } 371 func TestTransactionAnnouncement(t *testing.T) { testSyncTransaction(t, false) } 372 373 func testSyncTransaction(t *testing.T, propagtion bool) { 374 // Create a protocol manager for transaction fetcher and sender 375 pmFetcher, _ := newTestProtocolManagerMust(t, downloader.FastSync, 0, nil, nil) 376 defer pmFetcher.Stop() 377 pmSender, _ := newTestProtocolManagerMust(t, downloader.FastSync, 1024, nil, nil) 378 pmSender.broadcastTxAnnouncesOnly = !propagtion 379 defer pmSender.Stop() 380 381 // Sync up the two peers 382 io1, io2 := p2p.MsgPipe() 383 384 go pmSender.handle(pmSender.newPeer(65, p2p.NewPeer(enode.ID{}, "sender", nil), io2, pmSender.txpool.Get)) 385 go pmFetcher.handle(pmFetcher.newPeer(65, p2p.NewPeer(enode.ID{}, "fetcher", nil), io1, pmFetcher.txpool.Get)) 386 387 time.Sleep(250 * time.Millisecond) 388 pmFetcher.doSync(peerToSyncOp(downloader.FullSync, pmFetcher.peers.BestPeer())) 389 atomic.StoreUint32(&pmFetcher.acceptTxs, 1) 390 391 newTxs := make(chan core.NewTxsEvent, 1024) 392 sub := pmFetcher.txpool.SubscribeNewTxsEvent(newTxs) 393 defer sub.Unsubscribe() 394 395 // Fill the pool with new transactions 396 alltxs := make([]*types.Transaction, 1024) 397 for nonce := range alltxs { 398 alltxs[nonce] = newTestTransaction(testAccount, uint64(nonce), 0) 399 } 400 pmSender.txpool.AddRemotes(alltxs) 401 402 var got int 403 loop: 404 for { 405 select { 406 case ev := <-newTxs: 407 got += len(ev.Txs) 408 if got == 1024 { 409 break loop 410 } 411 case <-time.NewTimer(time.Second).C: 412 t.Fatal("Failed to retrieve all transaction") 413 } 414 } 415 } 416 417 // Tests that the custom union field encoder and decoder works correctly. 418 func TestGetBlockHeadersDataEncodeDecode(t *testing.T) { 419 // Create a "random" hash for testing 420 var hash common.Hash 421 for i := range hash { 422 hash[i] = byte(i) 423 } 424 // Assemble some table driven tests 425 tests := []struct { 426 packet *getBlockHeadersData 427 fail bool 428 }{ 429 // Providing the origin as either a hash or a number should both work 430 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Number: 314}}}, 431 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}}}, 432 433 // Providing arbitrary query field should also work 434 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Number: 314}, Amount: 314, Skip: 1, Reverse: true}}, 435 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: 314, Skip: 1, Reverse: true}}, 436 437 // Providing both the origin hash and origin number must fail 438 {fail: true, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash, Number: 314}}}, 439 } 440 // Iterate over each of the tests and try to encode and then decode 441 for i, tt := range tests { 442 bytes, err := rlp.EncodeToBytes(tt.packet) 443 if err != nil && !tt.fail { 444 t.Fatalf("test %d: failed to encode packet: %v", i, err) 445 } else if err == nil && tt.fail { 446 t.Fatalf("test %d: encode should have failed", i) 447 } 448 if !tt.fail { 449 packet := new(getBlockHeadersData) 450 if err := rlp.DecodeBytes(bytes, packet); err != nil { 451 t.Fatalf("test %d: failed to decode packet: %v", i, err) 452 } 453 if packet.Origin.Hash != tt.packet.Origin.Hash || packet.Origin.Number != tt.packet.Origin.Number || packet.Amount != tt.packet.Amount || 454 packet.Skip != tt.packet.Skip || packet.Reverse != tt.packet.Reverse { 455 t.Fatalf("test %d: encode decode mismatch: have %+v, want %+v", i, packet, tt.packet) 456 } 457 } 458 } 459 }