github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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 "sync" 22 "testing" 23 "time" 24 25 "github.com/ethereumproject/go-ethereum/common" 26 "github.com/ethereumproject/go-ethereum/core/types" 27 "github.com/ethereumproject/go-ethereum/crypto" 28 "github.com/ethereumproject/go-ethereum/eth/downloader" 29 "github.com/ethereumproject/go-ethereum/p2p" 30 "github.com/ethereumproject/go-ethereum/rlp" 31 ) 32 33 func init() { 34 // glog.SetToStderr(true) 35 // glog.SetV(6) 36 } 37 38 var testAccount, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 39 40 // Tests that handshake failures are detected and reported correctly. 41 func TestStatusMsgErrors61(t *testing.T) { testStatusMsgErrors(t, 61) } 42 func TestStatusMsgErrors62(t *testing.T) { testStatusMsgErrors(t, 62) } 43 func TestStatusMsgErrors63(t *testing.T) { testStatusMsgErrors(t, 63) } 44 45 func testStatusMsgErrors(t *testing.T, protocol int) { 46 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 47 td, currentBlock, genesis := pm.blockchain.Status() 48 defer pm.Stop() 49 50 tests := []struct { 51 code uint64 52 data interface{} 53 wantError error 54 }{ 55 { 56 code: TxMsg, data: []interface{}{}, 57 wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"), 58 }, 59 { 60 code: StatusMsg, data: statusData{10, NetworkId, td, currentBlock, genesis}, 61 wantError: errResp(ErrProtocolVersionMismatch, "10 (!= %d)", protocol), 62 }, 63 { 64 code: StatusMsg, data: statusData{uint32(protocol), 999, td, currentBlock, genesis}, 65 wantError: errResp(ErrNetworkIdMismatch, "999 (!= 1)"), 66 }, 67 { 68 code: StatusMsg, data: statusData{uint32(protocol), NetworkId, td, currentBlock, common.Hash{3}}, 69 wantError: errResp(ErrGenesisBlockMismatch, "0300000000000000000000000000000000000000000000000000000000000000 (!= %x…)", genesis.Bytes()[:8]), 70 }, 71 } 72 73 for i, test := range tests { 74 p, errc := newTestPeer("peer", protocol, pm, false) 75 // The send call might hang until reset because 76 // the protocol might not read the payload. 77 go p2p.Send(p.app, test.code, test.data) 78 79 select { 80 case err := <-errc: 81 if err == nil { 82 t.Errorf("test %d: protocol returned nil error, want %q", i, test.wantError) 83 } else if err.Error() != test.wantError.Error() { 84 t.Errorf("test %d: wrong error: got %q, want %q", i, err, test.wantError) 85 } 86 case <-time.After(2 * time.Second): 87 t.Errorf("protocol did not shut down withing 2 seconds") 88 } 89 p.close() 90 } 91 } 92 93 // This test checks that received transactions are added to the local pool. 94 func TestRecvTransactions61(t *testing.T) { testRecvTransactions(t, 61) } 95 func TestRecvTransactions62(t *testing.T) { testRecvTransactions(t, 62) } 96 func TestRecvTransactions63(t *testing.T) { testRecvTransactions(t, 63) } 97 98 func testRecvTransactions(t *testing.T, protocol int) { 99 txAdded := make(chan []*types.Transaction) 100 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, txAdded) 101 pm.acceptsTxs = 1 // mark synced to accept transactions 102 p, _ := newTestPeer("peer", protocol, pm, true) 103 defer pm.Stop() 104 defer p.close() 105 106 tx := newTestTransaction(testAccount, 0, 0) 107 if s, err := p2p.Send(p.app, TxMsg, []interface{}{tx}); err != nil { 108 t.Fatalf("send error: %v", err) 109 } else if s <= 0 { 110 t.Errorf("got: %v, want: >0", s) 111 } 112 select { 113 case added := <-txAdded: 114 if len(added) != 1 { 115 t.Errorf("wrong number of added transactions: got %d, want 1", len(added)) 116 } else if added[0].Hash() != tx.Hash() { 117 t.Errorf("added wrong tx hash: got %v, want %v", added[0].Hash(), tx.Hash()) 118 } 119 case <-time.After(2 * time.Second): 120 t.Errorf("no TxPreEvent received within 2 seconds") 121 } 122 } 123 124 // This test checks that pending transactions are sent. 125 func TestSendTransactions61(t *testing.T) { testSendTransactions(t, 61) } 126 func TestSendTransactions62(t *testing.T) { testSendTransactions(t, 62) } 127 func TestSendTransactions63(t *testing.T) { testSendTransactions(t, 63) } 128 129 func testSendTransactions(t *testing.T, protocol int) { 130 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 131 defer pm.Stop() 132 133 // Fill the pool with big transactions. 134 const txsize = txsyncPackSize / 10 135 alltxs := make([]*types.Transaction, 100) 136 for nonce := range alltxs { 137 alltxs[nonce] = newTestTransaction(testAccount, uint64(nonce), txsize) 138 } 139 pm.txpool.AddTransactions(alltxs) 140 141 // Connect several peers. They should all receive the pending transactions. 142 var wg sync.WaitGroup 143 checktxs := func(p *testPeer) { 144 defer wg.Done() 145 defer p.close() 146 seen := make(map[common.Hash]bool) 147 for _, tx := range alltxs { 148 seen[tx.Hash()] = false 149 } 150 for n := 0; n < len(alltxs) && !t.Failed(); { 151 var txs []*types.Transaction 152 msg, err := p.app.ReadMsg() 153 if err != nil { 154 t.Errorf("%v: read error: %v", p.Peer, err) 155 } else if msg.Code != TxMsg { 156 t.Errorf("%v: got code %d, want TxMsg", p.Peer, msg.Code) 157 } 158 if err := msg.Decode(&txs); err != nil { 159 t.Errorf("%v: %v", p.Peer, err) 160 } 161 for _, tx := range txs { 162 hash := tx.Hash() 163 seentx, want := seen[hash] 164 if seentx { 165 t.Errorf("%v: got tx more than once: %x", p.Peer, hash) 166 } 167 if !want { 168 t.Errorf("%v: got unexpected tx: %x", p.Peer, hash) 169 } 170 seen[hash] = true 171 n++ 172 } 173 } 174 } 175 for i := 0; i < 3; i++ { 176 p, _ := newTestPeer(fmt.Sprintf("peer #%d", i), protocol, pm, true) 177 wg.Add(1) 178 go checktxs(p) 179 } 180 wg.Wait() 181 } 182 183 // Tests that the custom union field encoder and decoder works correctly. 184 func TestGetBlockHeadersDataEncodeDecode(t *testing.T) { 185 // Create a "random" hash for testing 186 var hash common.Hash 187 for i := range hash { 188 hash[i] = byte(i) 189 } 190 // Assemble some table driven tests 191 tests := []struct { 192 packet *getBlockHeadersData 193 fail bool 194 }{ 195 // Providing the origin as either a hash or a number should both work 196 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Number: 314}}}, 197 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}}}, 198 199 // Providing arbitrary query field should also work 200 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Number: 314}, Amount: 314, Skip: 1, Reverse: true}}, 201 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: 314, Skip: 1, Reverse: true}}, 202 203 // Providing both the origin hash and origin number must fail 204 {fail: true, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash, Number: 314}}}, 205 } 206 // Iterate over each of the tests and try to encode and then decode 207 for i, tt := range tests { 208 bytes, err := rlp.EncodeToBytes(tt.packet) 209 if err != nil && !tt.fail { 210 t.Fatalf("test %d: failed to encode packet: %v", i, err) 211 } else if err == nil && tt.fail { 212 t.Fatalf("test %d: encode should have failed", i) 213 } 214 if !tt.fail { 215 packet := new(getBlockHeadersData) 216 if err := rlp.DecodeBytes(bytes, packet); err != nil { 217 t.Fatalf("test %d: failed to decode packet: %v", i, err) 218 } 219 if packet.Origin.Hash != tt.packet.Origin.Hash || packet.Origin.Number != tt.packet.Origin.Number || packet.Amount != tt.packet.Amount || 220 packet.Skip != tt.packet.Skip || packet.Reverse != tt.packet.Reverse { 221 t.Fatalf("test %d: encode decode mismatch: have %+v, want %+v", i, packet, tt.packet) 222 } 223 } 224 } 225 }