github.com/klaytn/klaytn@v1.12.1/node/sc/subbridge_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package sc 18 19 import ( 20 "fmt" 21 "math/big" 22 "os" 23 "reflect" 24 "strings" 25 "testing" 26 27 "github.com/golang/mock/gomock" 28 "github.com/klaytn/klaytn/accounts" 29 "github.com/klaytn/klaytn/crypto" 30 "github.com/klaytn/klaytn/event" 31 "github.com/klaytn/klaytn/networks/p2p" 32 "github.com/klaytn/klaytn/networks/p2p/discover" 33 "github.com/klaytn/klaytn/node" 34 "github.com/stretchr/testify/assert" 35 ) 36 37 // testNewSubBridge returns a test SubBridge. 38 func testNewSubBridge(t *testing.T) *SubBridge { 39 tempDir, err := os.MkdirTemp(os.TempDir(), "klaytn-test-sb-") 40 if err != nil { 41 t.Fatal(err) 42 } 43 44 sCtx := node.NewServiceContext(&node.DefaultConfig, map[reflect.Type]node.Service{}, &event.TypeMux{}, &accounts.Manager{}) 45 sBridge, err := NewSubBridge(sCtx, &SCConfig{NetworkId: testNetVersion, DataDir: tempDir}) 46 if err != nil { 47 t.Fatal(err) 48 } 49 assert.NotNil(t, sBridge) 50 51 return sBridge 52 } 53 54 // removeData removes blockchain data generated during the SubBridge test. 55 func (sb *SubBridge) removeData(t *testing.T) { 56 if err := os.RemoveAll(sb.config.DataDir); err != nil { 57 t.Fatal(err) 58 } 59 } 60 61 // TestSubBridge_basic tests some getters and basic operation of SubBridge. 62 func TestSubBridge_basic(t *testing.T) { 63 // Create a test SubBridge 64 sBridge := testNewSubBridge(t) 65 defer sBridge.removeData(t) 66 67 // APIs returns default rpc APIs of MainBridge 68 apis := sBridge.APIs() 69 assert.Equal(t, 2, len(apis)) 70 assert.Equal(t, "subbridge", apis[0].Namespace) 71 assert.Equal(t, "subbridge", apis[1].Namespace) 72 73 // Test getters for elements of SubBridge 74 assert.Equal(t, true, sBridge.IsListening()) // Always returns `true` 75 assert.Equal(t, testProtocolVersion, sBridge.ProtocolVersion()) 76 assert.Equal(t, testNetVersion, sBridge.NetVersion()) 77 78 // New components of MainBridge which will update old components 79 bc := testBlockChain(t) 80 txPool := testTxPool(sBridge.config.DataDir, bc) 81 82 var comp []interface{} 83 comp = append(comp, bc) 84 comp = append(comp, txPool) 85 86 // Check initial status of components 87 assert.Nil(t, sBridge.blockchain) 88 assert.Nil(t, sBridge.txPool) 89 90 // Update and check MainBridge components 91 sBridge.SetComponents(comp) 92 assert.Equal(t, bc, sBridge.blockchain) 93 assert.Equal(t, txPool, sBridge.txPool) 94 95 // Start MainBridge and stop later 96 if err := sBridge.Start(p2p.SingleChannelServer{}); err != nil { 97 t.Fatal(err) 98 } 99 defer sBridge.Stop() 100 101 // TODO more test 102 } 103 104 // TestSubBridge_removePeer tests correct removal of a peer from `SubBridge.peers`. 105 func TestSubBridge_removePeer(t *testing.T) { 106 // Create a test SubBridge (it may have 0 peers) 107 sBridge := testNewSubBridge(t) 108 defer sBridge.removeData(t) 109 defer sBridge.chainDB.Close() 110 111 // Set components of SubBridge 112 bc := testBlockChain(t) 113 txPool := testTxPool(sBridge.config.DataDir, bc) 114 115 var comp []interface{} 116 comp = append(comp, bc) 117 comp = append(comp, txPool) 118 119 sBridge.SetComponents(comp) 120 121 // Prepare information of bridgePeer to be added and removed 122 nodeID := "0x1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d" 123 peer := p2p.NewPeer(discover.MustHexID(nodeID), "name", []p2p.Cap{}) 124 peerID := peer.ID() 125 bridgePeerID := fmt.Sprintf("%x", peerID[:8]) 126 127 // mockBridgePeer mocks BridgePeer 128 mockCtrl := gomock.NewController(t) 129 defer mockCtrl.Finish() 130 131 mockBridgePeer := NewMockBridgePeer(mockCtrl) 132 mockBridgePeer.EXPECT().GetID().Return(bridgePeerID).AnyTimes() 133 mockBridgePeer.EXPECT().GetChainID().Return(big.NewInt(0)).AnyTimes() 134 mockBridgePeer.EXPECT().GetP2PPeer().Return(peer).AnyTimes() 135 mockBridgePeer.EXPECT().SendServiceChainInfoRequest(gomock.Any()).Return(nil).AnyTimes() 136 mockBridgePeer.EXPECT().Close().Return().AnyTimes() 137 138 // Add the bridgePeer 139 if err := sBridge.peers.Register(mockBridgePeer); err != nil { 140 t.Fatal(err) 141 } 142 if err := sBridge.handler.RegisterNewPeer(mockBridgePeer); err != nil { 143 t.Fatal(err) 144 } 145 146 peerNum := sBridge.peers.Len() 147 148 // Try to remove a non-registered bridgePeer, and nothing happen 149 sBridge.removePeer("0x11111111") 150 assert.Equal(t, peerNum, sBridge.peers.Len()) 151 152 // Remove the registered bridgePeer 153 sBridge.removePeer(mockBridgePeer.GetID()) 154 assert.Equal(t, peerNum-1, sBridge.peers.Len()) 155 } 156 157 // TestSubBridge_handleMsg fails when a bridgePeer fails to read a message or reads a too long message. 158 func TestSubBridge_handleMsg(t *testing.T) { 159 // Create a test SubBridge 160 sBridge := testNewSubBridge(t) 161 defer sBridge.removeData(t) 162 defer sBridge.chainDB.Close() 163 164 // Elements for a bridgePeer 165 key, _ := crypto.GenerateKey() 166 nodeID := discover.PubkeyID(&key.PublicKey) 167 peer := p2p.NewPeer(nodeID, "name", []p2p.Cap{}) 168 pipe1, pipe2 := p2p.MsgPipe() 169 170 // bridgePeer will receive a message through rw1 171 bridgePeer := newBridgePeer(testProtocolVersion, peer, pipe1) 172 173 // Case1. Send a valid message and handle it successfully 174 { 175 data := "valid message" 176 go func() { 177 if err := p2p.Send(pipe2, StatusMsg, data); err != nil { 178 t.Error(err) 179 return 180 } 181 }() 182 183 if err := sBridge.handleMsg(bridgePeer); err != nil { 184 t.Fatal(err) 185 } 186 } 187 188 // Case2. Send an invalid message having large size and fail to handle 189 { 190 data := strings.Repeat("a", ProtocolMaxMsgSize+1) 191 go func() { 192 if err := p2p.Send(pipe2, StatusMsg, data); err != nil { 193 t.Error(err) 194 return 195 } 196 }() 197 198 err := sBridge.handleMsg(bridgePeer) 199 assert.True(t, strings.HasPrefix(err.Error(), "Message too long")) 200 } 201 202 // Case3. Return an error when it fails to read a message 203 { 204 _ = pipe2.Close() 205 206 err := sBridge.handleMsg(bridgePeer) 207 assert.Equal(t, p2p.ErrPipeClosed, err) 208 209 } 210 _ = pipe1.Close() 211 } 212 213 // TestSubBridge_handle tests the fail cases of `handle` function. 214 // There are no success cases in this test since `handle` has a infinite loop inside. 215 func TestSubBridge_handle(t *testing.T) { 216 // Create a test SubBridge 217 sBridge := testNewSubBridge(t) 218 defer sBridge.removeData(t) 219 defer sBridge.chainDB.Close() 220 221 // Set components of SubBridge 222 bc := testBlockChain(t) 223 txPool := testTxPool(sBridge.config.DataDir, bc) 224 225 var comp []interface{} 226 comp = append(comp, bc) 227 comp = append(comp, txPool) 228 229 sBridge.SetComponents(comp) 230 231 // Variables will be used as return values of mockBridgePeer 232 key, _ := crypto.GenerateKey() 233 nodeID := discover.PubkeyID(&key.PublicKey) 234 peer := p2p.NewPeer(nodeID, "name", []p2p.Cap{}) 235 peerID := peer.ID() 236 bridgePeerID := fmt.Sprintf("%x", peerID[:8]) 237 pipe, _ := p2p.MsgPipe() 238 239 // mockBridgePeer mocks BridgePeer 240 mockCtrl := gomock.NewController(t) 241 defer mockCtrl.Finish() 242 243 mockBridgePeer := NewMockBridgePeer(mockCtrl) 244 mockBridgePeer.EXPECT().GetID().Return(bridgePeerID).AnyTimes() 245 mockBridgePeer.EXPECT().GetChainID().Return(big.NewInt(0)).AnyTimes() 246 mockBridgePeer.EXPECT().GetP2PPeer().Return(peer).AnyTimes() 247 mockBridgePeer.EXPECT().GetP2PPeerID().Return(peerID).AnyTimes() 248 mockBridgePeer.EXPECT().GetRW().Return(pipe).AnyTimes() 249 mockBridgePeer.EXPECT().SendServiceChainInfoRequest(gomock.Any()).Return(nil).AnyTimes() 250 mockBridgePeer.EXPECT().Close().Return().AnyTimes() 251 252 // Case 1 - Error if `sBridge.peers.Len()` was equal or bigger than `sBridge.maxPeers` 253 { 254 // Set maxPeers to make the test fail 255 sBridge.maxPeers = sBridge.peers.Len() 256 257 err := sBridge.handle(mockBridgePeer) 258 assert.Equal(t, p2p.DiscTooManyPeers, err) 259 } 260 // Resolve the above failure condition by increasing maxPeers 261 sBridge.maxPeers += 5 262 263 // Case 2 - Error if handshake of BridgePeer failed 264 { 265 // Make handshake fail 266 mockBridgePeer.EXPECT().Handshake(sBridge.networkId, sBridge.getChainID(), gomock.Any(), sBridge.blockchain.CurrentHeader().Hash()).Return(p2p.ErrPipeClosed).Times(1) 267 268 err := sBridge.handle(mockBridgePeer) 269 assert.Equal(t, p2p.ErrPipeClosed, err) 270 } 271 // Resolve the above failure condition by making handshake success 272 mockBridgePeer.EXPECT().Handshake(sBridge.networkId, sBridge.getChainID(), gomock.Any(), sBridge.blockchain.CurrentHeader().Hash()).Return(nil).AnyTimes() 273 274 // Case 3 - Error when the same peer was registered before 275 { 276 // Pre-register a peer which will be added again 277 sBridge.peers.peers[bridgePeerID] = &baseBridgePeer{} 278 279 err := sBridge.handle(mockBridgePeer) 280 assert.Equal(t, errAlreadyRegistered, err) 281 } 282 // Resolve the above failure condition by deleting the registered peer 283 delete(sBridge.peers.peers, bridgePeerID) 284 285 // Case 4 - Error if `sBridge.handleMsg` failed 286 { 287 // Close of the peer's pipe make `sBridge.handleMsg` fail 288 _ = pipe.Close() 289 290 err := sBridge.handle(mockBridgePeer) 291 assert.Equal(t, p2p.ErrPipeClosed, err) 292 } 293 } 294 295 // TestSubBridge_SendRPCData tests SendRPCResponseData function of SubBridge. 296 // The function sends RPC response data to SubBridge's peers. 297 func TestSubBridge_SendRPCData(t *testing.T) { 298 // Create a test SubBridge 299 sBridge := testNewSubBridge(t) 300 defer sBridge.removeData(t) 301 defer sBridge.chainDB.Close() 302 303 // Test data used as a parameter of SendResponseRPC function 304 data := []byte{0x11, 0x22, 0x33} 305 306 // mockBridgePeer mocks BridgePeer 307 mockCtrl := gomock.NewController(t) 308 defer mockCtrl.Finish() 309 310 mockBridgePeer := NewMockBridgePeer(mockCtrl) 311 mockBridgePeer.EXPECT().GetID().Return("testID").AnyTimes() // for `sBridge.BridgePeerSet().Register(mockBridgePeer)` 312 313 // Register mockBridgePeer as a peer of `sBridge.BridgePeerSet` 314 if err := sBridge.BridgePeerSet().Register(mockBridgePeer); err != nil { 315 t.Fatal(err) 316 } 317 318 // Case 1 - Error if SendResponseRPC of mockBridgePeer failed 319 { 320 // Make mockBridgePeer return an error 321 mockBridgePeer.EXPECT().SendRequestRPC(data).Return(p2p.ErrPipeClosed).Times(1) 322 323 err := sBridge.SendRPCData(data) 324 assert.Equal(t, p2p.ErrPipeClosed, err) 325 } 326 327 // Case 2 - Success if SendResponseRPC of mockBridgePeer succeeded 328 { 329 // Make mockBridgePeer return nil 330 mockBridgePeer.EXPECT().SendRequestRPC(data).Return(nil).Times(1) 331 332 err := sBridge.SendRPCData(data) 333 assert.Equal(t, nil, err) 334 } 335 }