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