github.com/karalabe/go-ethereum@v0.8.5/eth/protocol_test.go (about) 1 package eth 2 3 import ( 4 "bytes" 5 "io" 6 "log" 7 "math/big" 8 "os" 9 "testing" 10 "time" 11 12 "github.com/ethereum/go-ethereum/core/types" 13 "github.com/ethereum/go-ethereum/crypto" 14 "github.com/ethereum/go-ethereum/ethutil" 15 ethlogger "github.com/ethereum/go-ethereum/logger" 16 "github.com/ethereum/go-ethereum/p2p" 17 "github.com/ethereum/go-ethereum/p2p/discover" 18 ) 19 20 var sys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel)) 21 22 type testMsgReadWriter struct { 23 in chan p2p.Msg 24 out []p2p.Msg 25 } 26 27 func (self *testMsgReadWriter) In(msg p2p.Msg) { 28 self.in <- msg 29 } 30 31 func (self *testMsgReadWriter) Out() (msg p2p.Msg, ok bool) { 32 if len(self.out) > 0 { 33 msg = self.out[0] 34 self.out = self.out[1:] 35 ok = true 36 } 37 return 38 } 39 40 func (self *testMsgReadWriter) WriteMsg(msg p2p.Msg) error { 41 self.out = append(self.out, msg) 42 return nil 43 } 44 45 func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) { 46 msg, ok := <-self.in 47 if !ok { 48 return msg, io.EOF 49 } 50 return msg, nil 51 } 52 53 type testTxPool struct { 54 getTransactions func() []*types.Transaction 55 addTransactions func(txs []*types.Transaction) 56 } 57 58 type testChainManager struct { 59 getBlockHashes func(hash []byte, amount uint64) (hashes [][]byte) 60 getBlock func(hash []byte) *types.Block 61 status func() (td *big.Int, currentBlock []byte, genesisBlock []byte) 62 } 63 64 type testBlockPool struct { 65 addBlockHashes func(next func() ([]byte, bool), peerId string) 66 addBlock func(block *types.Block, peerId string) (err error) 67 addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(int, string, ...interface{})) (best bool) 68 removePeer func(peerId string) 69 } 70 71 // func (self *testTxPool) GetTransactions() (txs []*types.Transaction) { 72 // if self.getTransactions != nil { 73 // txs = self.getTransactions() 74 // } 75 // return 76 // } 77 78 func (self *testTxPool) AddTransactions(txs []*types.Transaction) { 79 if self.addTransactions != nil { 80 self.addTransactions(txs) 81 } 82 } 83 84 func (self *testTxPool) GetTransactions() types.Transactions { return nil } 85 86 func (self *testChainManager) GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) { 87 if self.getBlockHashes != nil { 88 hashes = self.getBlockHashes(hash, amount) 89 } 90 return 91 } 92 93 func (self *testChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { 94 if self.status != nil { 95 td, currentBlock, genesisBlock = self.status() 96 } 97 return 98 } 99 100 func (self *testChainManager) GetBlock(hash []byte) (block *types.Block) { 101 if self.getBlock != nil { 102 block = self.getBlock(hash) 103 } 104 return 105 } 106 107 func (self *testBlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) { 108 if self.addBlockHashes != nil { 109 self.addBlockHashes(next, peerId) 110 } 111 } 112 113 func (self *testBlockPool) AddBlock(block *types.Block, peerId string) { 114 if self.addBlock != nil { 115 self.addBlock(block, peerId) 116 } 117 } 118 119 func (self *testBlockPool) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(int, string, ...interface{})) (best bool) { 120 if self.addPeer != nil { 121 best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError) 122 } 123 return 124 } 125 126 func (self *testBlockPool) RemovePeer(peerId string) { 127 if self.removePeer != nil { 128 self.removePeer(peerId) 129 } 130 } 131 132 func testPeer() *p2p.Peer { 133 var id discover.NodeID 134 pk := crypto.GenerateNewKeyPair().PublicKey 135 copy(id[:], pk) 136 return p2p.NewPeer(id, "test peer", []p2p.Cap{}) 137 } 138 139 type ethProtocolTester struct { 140 quit chan error 141 rw *testMsgReadWriter // p2p.MsgReadWriter 142 txPool *testTxPool // txPool 143 chainManager *testChainManager // chainManager 144 blockPool *testBlockPool // blockPool 145 t *testing.T 146 } 147 148 func newEth(t *testing.T) *ethProtocolTester { 149 return ðProtocolTester{ 150 quit: make(chan error), 151 rw: &testMsgReadWriter{in: make(chan p2p.Msg, 10)}, 152 txPool: &testTxPool{}, 153 chainManager: &testChainManager{}, 154 blockPool: &testBlockPool{}, 155 t: t, 156 } 157 } 158 159 func (self *ethProtocolTester) reset() { 160 self.rw = &testMsgReadWriter{in: make(chan p2p.Msg, 10)} 161 self.quit = make(chan error) 162 } 163 164 func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err error) { 165 var timer = time.After(delay) 166 select { 167 case err = <-self.quit: 168 case <-timer: 169 self.t.Errorf("no error after %v, expected %v", delay, expCode) 170 return 171 } 172 perr, ok := err.(*protocolError) 173 if ok && perr != nil { 174 if code := perr.Code; code != expCode { 175 self.t.Errorf("expected protocol error (code %v), got %v (%v)", expCode, code, err) 176 } 177 } else { 178 self.t.Errorf("expected protocol error (code %v), got %v", expCode, err) 179 } 180 return 181 } 182 183 func (self *ethProtocolTester) In(msg p2p.Msg) { 184 self.rw.In(msg) 185 } 186 187 func (self *ethProtocolTester) Out() (p2p.Msg, bool) { 188 return self.rw.Out() 189 } 190 191 func (self *ethProtocolTester) checkMsg(i int, code uint64, val interface{}) (msg p2p.Msg) { 192 if i >= len(self.rw.out) { 193 self.t.Errorf("expected at least %v msgs, got %v", i, len(self.rw.out)) 194 return 195 } 196 msg = self.rw.out[i] 197 if msg.Code != code { 198 self.t.Errorf("expected msg code %v, got %v", code, msg.Code) 199 } 200 if val != nil { 201 if err := msg.Decode(val); err != nil { 202 self.t.Errorf("rlp encoding error: %v", err) 203 } 204 } 205 return 206 } 207 208 func (self *ethProtocolTester) run() { 209 err := runEthProtocol(self.txPool, self.chainManager, self.blockPool, testPeer(), self.rw) 210 self.quit <- err 211 } 212 213 func TestStatusMsgErrors(t *testing.T) { 214 logInit() 215 eth := newEth(t) 216 td := ethutil.Big1 217 currentBlock := []byte{1} 218 genesis := []byte{2} 219 eth.chainManager.status = func() (*big.Int, []byte, []byte) { return td, currentBlock, genesis } 220 go eth.run() 221 statusMsg := p2p.NewMsg(4) 222 eth.In(statusMsg) 223 delay := 1 * time.Second 224 eth.checkError(ErrNoStatusMsg, delay) 225 var status statusMsgData 226 eth.checkMsg(0, StatusMsg, &status) // first outgoing msg should be StatusMsg 227 if status.TD.Cmp(td) != 0 || 228 status.ProtocolVersion != ProtocolVersion || 229 status.NetworkId != NetworkId || 230 status.TD.Cmp(td) != 0 || 231 bytes.Compare(status.CurrentBlock, currentBlock) != 0 || 232 bytes.Compare(status.GenesisBlock, genesis) != 0 { 233 t.Errorf("incorrect outgoing status") 234 } 235 236 eth.reset() 237 go eth.run() 238 statusMsg = p2p.NewMsg(0, uint32(48), uint32(0), td, currentBlock, genesis) 239 eth.In(statusMsg) 240 eth.checkError(ErrProtocolVersionMismatch, delay) 241 242 eth.reset() 243 go eth.run() 244 statusMsg = p2p.NewMsg(0, uint32(49), uint32(1), td, currentBlock, genesis) 245 eth.In(statusMsg) 246 eth.checkError(ErrNetworkIdMismatch, delay) 247 248 eth.reset() 249 go eth.run() 250 statusMsg = p2p.NewMsg(0, uint32(49), uint32(0), td, currentBlock, []byte{3}) 251 eth.In(statusMsg) 252 eth.checkError(ErrGenesisBlockMismatch, delay) 253 254 }