github.com/klaytn/klaytn@v1.12.1/node/sc/mainbridge_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 "path" 23 "reflect" 24 "strings" 25 "testing" 26 27 "github.com/golang/mock/gomock" 28 "github.com/klaytn/klaytn/accounts" 29 "github.com/klaytn/klaytn/api" 30 "github.com/klaytn/klaytn/blockchain" 31 "github.com/klaytn/klaytn/blockchain/vm" 32 "github.com/klaytn/klaytn/common" 33 "github.com/klaytn/klaytn/consensus/istanbul" 34 "github.com/klaytn/klaytn/consensus/istanbul/backend" 35 "github.com/klaytn/klaytn/crypto" 36 "github.com/klaytn/klaytn/event" 37 "github.com/klaytn/klaytn/governance" 38 "github.com/klaytn/klaytn/networks/p2p" 39 "github.com/klaytn/klaytn/networks/p2p/discover" 40 "github.com/klaytn/klaytn/networks/rpc" 41 "github.com/klaytn/klaytn/node" 42 "github.com/klaytn/klaytn/node/cn" 43 "github.com/klaytn/klaytn/params" 44 "github.com/klaytn/klaytn/storage/database" 45 "github.com/stretchr/testify/assert" 46 ) 47 48 const testNetVersion = uint64(8888) 49 50 var testProtocolVersion = int(SCProtocolVersion[0]) 51 52 // testNewMainBridge returns a test MainBridge. 53 func testNewMainBridge(t *testing.T) *MainBridge { 54 sCtx := node.NewServiceContext(&node.DefaultConfig, map[reflect.Type]node.Service{}, &event.TypeMux{}, &accounts.Manager{}) 55 mBridge, err := NewMainBridge(sCtx, &SCConfig{NetworkId: testNetVersion}) 56 if err != nil { 57 t.Fatal(err) 58 } 59 assert.NotNil(t, mBridge) 60 61 return mBridge 62 } 63 64 // testBlockChain returns a test BlockChain with initial values 65 func testBlockChain(t *testing.T) *blockchain.BlockChain { 66 db := database.NewMemoryDBManager() 67 68 gov := governance.NewMixedEngine(¶ms.ChainConfig{ 69 ChainID: big.NewInt(2018), 70 UnitPrice: 25000000000, 71 DeriveShaImpl: 0, 72 Istanbul: ¶ms.IstanbulConfig{ 73 Epoch: istanbul.DefaultConfig.Epoch, 74 ProposerPolicy: uint64(istanbul.DefaultConfig.ProposerPolicy), 75 SubGroupSize: istanbul.DefaultConfig.SubGroupSize, 76 }, 77 Governance: params.GetDefaultGovernanceConfig(), 78 }, db) 79 80 prvKey, _ := crypto.GenerateKey() 81 engine := backend.New(&backend.BackendOpts{ 82 IstanbulConfig: istanbul.DefaultConfig, 83 Rewardbase: common.Address{}, 84 PrivateKey: prvKey, 85 DB: db, 86 Governance: gov, 87 NodeType: common.CONSENSUSNODE, 88 }) 89 90 genesis := blockchain.DefaultGenesisBlock() 91 genesis.BlockScore = big.NewInt(1) 92 genesis.Config = params.CypressChainConfig.Copy() 93 genesis.Config.Governance = params.GetDefaultGovernanceConfig() 94 genesis.Config.Istanbul = params.GetDefaultIstanbulConfig() 95 genesis.Config.UnitPrice = 25 * params.Ston 96 97 chainConfig, _, err := blockchain.SetupGenesisBlock(db, genesis, params.UnusedNetworkId, false, false) 98 if _, ok := err.(*params.ConfigCompatError); err != nil && !ok { 99 t.Fatal(err) 100 } 101 102 bc, err := blockchain.NewBlockChain(db, nil, chainConfig, engine, vm.Config{}) 103 if err != nil { 104 t.Fatal(err) 105 } 106 return bc 107 } 108 109 func testTxPool(dataDir string, bc *blockchain.BlockChain) *blockchain.TxPool { 110 blockchain.DefaultTxPoolConfig.Journal = path.Join(dataDir, blockchain.DefaultTxPoolConfig.Journal) 111 return blockchain.NewTxPool(blockchain.DefaultTxPoolConfig, bc.Config(), bc) 112 } 113 114 // TestCreateDB tests creation of chain database and proper working of database operation. 115 func TestCreateDB(t *testing.T) { 116 sCtx := node.NewServiceContext(&node.DefaultConfig, map[reflect.Type]node.Service{}, &event.TypeMux{}, &accounts.Manager{}) 117 sConfig := &SCConfig{} 118 name := "testDB" 119 120 // Create a DB Manager 121 dbManager := CreateDB(sCtx, sConfig, name) 122 defer dbManager.Close() 123 assert.NotNil(t, dbManager) 124 125 // Check initial DBConfig of `CreateDB()` 126 dbConfig := dbManager.GetDBConfig() 127 assert.True(t, strings.HasSuffix(dbConfig.Dir, name)) 128 assert.Equal(t, database.LevelDB, dbConfig.DBType) 129 } 130 131 // TestMainBridge_basic tests some getters and basic operation of MainBridge. 132 func TestMainBridge_basic(t *testing.T) { 133 // Create a test MainBridge 134 mBridge := testNewMainBridge(t) 135 136 // APIs returns default rpc APIs of MainBridge 137 apis := mBridge.APIs() 138 assert.Equal(t, 2, len(apis)) 139 assert.Equal(t, "mainbridge", apis[0].Namespace) 140 assert.Equal(t, "mainbridge", apis[1].Namespace) 141 142 // Test getters for elements of MainBridge 143 assert.Equal(t, true, mBridge.IsListening()) // Always returns `true` 144 assert.Equal(t, testProtocolVersion, mBridge.ProtocolVersion()) 145 assert.Equal(t, testNetVersion, mBridge.NetVersion()) 146 147 // New components of MainBridge which will update old components 148 bc := &blockchain.BlockChain{} 149 txPool := &blockchain.TxPool{} 150 compAPIs := []rpc.API{ 151 { 152 Namespace: "klay", 153 Version: "1.0", 154 Service: api.NewPublicKlayAPI(&cn.CNAPIBackend{}), 155 Public: true, 156 }, 157 } 158 var comp []interface{} 159 comp = append(comp, bc) 160 comp = append(comp, txPool) 161 comp = append(comp, compAPIs) 162 163 // Check initial status of components 164 assert.Nil(t, mBridge.blockchain) 165 assert.Nil(t, mBridge.txPool) 166 // return structure has been changed when no service has been registered yet. 167 // before modification: return type is nil 168 // after modification: return type is "nil, map[nil], map[nil], which equals to service{}" 169 // rpc.GetNullServices() returns service{} 170 assert.Equal(t, rpc.GetNullServices(), mBridge.rpcServer.GetServices()["klay"]) 171 172 // Update and check MainBridge components 173 mBridge.SetComponents(comp) 174 assert.Equal(t, bc, mBridge.blockchain) 175 assert.Equal(t, txPool, mBridge.txPool) 176 assert.NotNil(t, mBridge.rpcServer.GetServices()["klay"]) 177 178 // Start MainBridge and stop later 179 if err := mBridge.Start(p2p.SingleChannelServer{}); err != nil { 180 t.Fatal(err) 181 } 182 defer mBridge.Stop() 183 184 // TODO more test 185 } 186 187 // TestMainBridge_removePeer tests correct removal of a peer from `MainBridge.peers`. 188 func TestMainBridge_removePeer(t *testing.T) { 189 // Create a MainBridge (it may have 0 peers) 190 mBridge := testNewMainBridge(t) 191 defer mBridge.chainDB.Close() 192 193 // Prepare a bridgePeer to be added and removed 194 nodeID := "0x1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d" 195 peer := p2p.NewPeer(discover.MustHexID(nodeID), "name", []p2p.Cap{}) 196 bridgePeer := mBridge.newPeer(1, peer, &p2p.MsgPipeRW{}) 197 198 // Add the bridgePeer 199 if err := mBridge.peers.Register(bridgePeer); err != nil { 200 t.Fatal(err) 201 } 202 peerNum := mBridge.peers.Len() 203 204 // Try to remove a non-registered bridgePeer, and nothing happen 205 mBridge.removePeer("0x11111111") 206 assert.Equal(t, peerNum, mBridge.peers.Len()) 207 208 // Remove the registered bridgePeer 209 mBridge.removePeer(bridgePeer.GetID()) 210 assert.Equal(t, peerNum-1, mBridge.peers.Len()) 211 } 212 213 // TestMainBridge_handleMsg fails when a bridgePeer fails to read a message or reads a too long message. 214 func TestMainBridge_handleMsg(t *testing.T) { 215 // Create a MainBridge 216 mBridge := testNewMainBridge(t) 217 defer mBridge.chainDB.Close() 218 219 // Elements for a bridgePeer 220 key, _ := crypto.GenerateKey() 221 nodeID := discover.PubkeyID(&key.PublicKey) 222 peer := p2p.NewPeer(nodeID, "name", []p2p.Cap{}) 223 pipe1, pipe2 := p2p.MsgPipe() 224 225 // bridgePeer will receive a message through rw1 226 bridgePeer := newBridgePeer(testProtocolVersion, peer, pipe1) 227 228 // Case1. Send a valid message and handle it successfully 229 { 230 data := "valid message" 231 go func() { 232 if err := p2p.Send(pipe2, StatusMsg, data); err != nil { 233 t.Error(err) 234 return 235 } 236 }() 237 238 if err := mBridge.handleMsg(bridgePeer); err != nil { 239 t.Fatal(err) 240 } 241 } 242 243 // Case2. Send an invalid message having large size and fail to handle 244 { 245 data := strings.Repeat("a", ProtocolMaxMsgSize+1) 246 go func() { 247 if err := p2p.Send(pipe2, StatusMsg, data); err != nil { 248 t.Error(err) 249 return 250 } 251 }() 252 253 err := mBridge.handleMsg(bridgePeer) 254 assert.True(t, strings.HasPrefix(err.Error(), "Message too long")) 255 } 256 257 // Case3. Return an error when it fails to read a message 258 { 259 _ = pipe2.Close() 260 261 err := mBridge.handleMsg(bridgePeer) 262 assert.Equal(t, p2p.ErrPipeClosed, err) 263 264 } 265 _ = pipe1.Close() 266 } 267 268 // TestMainBridge_handle tests the fail cases of `handle` function. 269 // There are no success cases in this test since `handle` has a infinite loop inside. 270 func TestMainBridge_handle(t *testing.T) { 271 // Create a MainBridge 272 mBridge := testNewMainBridge(t) 273 defer mBridge.chainDB.Close() 274 275 // Set testBlockChain to MainBridge.blockchain 276 mBridge.blockchain = testBlockChain(t) 277 278 // Variables will be used as return values of mockBridgePeer 279 key, _ := crypto.GenerateKey() 280 nodeID := discover.PubkeyID(&key.PublicKey) 281 peer := p2p.NewPeer(nodeID, "name", []p2p.Cap{}) 282 peerID := peer.ID() 283 bridgePeerID := fmt.Sprintf("%x", peerID[:8]) 284 pipe, _ := p2p.MsgPipe() 285 286 // mockBridgePeer mocks BridgePeer 287 mockCtrl := gomock.NewController(t) 288 defer mockCtrl.Finish() 289 290 mockBridgePeer := NewMockBridgePeer(mockCtrl) 291 mockBridgePeer.EXPECT().GetID().Return(bridgePeerID).AnyTimes() 292 mockBridgePeer.EXPECT().GetP2PPeer().Return(peer).AnyTimes() 293 mockBridgePeer.EXPECT().GetP2PPeerID().Return(peerID).AnyTimes() 294 mockBridgePeer.EXPECT().GetRW().Return(pipe).AnyTimes() 295 mockBridgePeer.EXPECT().Close().Return().AnyTimes() 296 297 // Case 1 - Error if `mBridge.peers.Len()` was equal or bigger than `mBridge.maxPeers` 298 { 299 // Set maxPeers to make the test fail 300 mBridge.maxPeers = mBridge.peers.Len() 301 302 err := mBridge.handle(mockBridgePeer) 303 assert.Equal(t, p2p.DiscTooManyPeers, err) 304 } 305 // Resolve the above failure condition by increasing maxPeers 306 mBridge.maxPeers += 5 307 308 // Case 2 - Error if handshake of BridgePeer failed 309 { 310 // Make handshake fail 311 mockBridgePeer.EXPECT().Handshake(mBridge.networkId, mBridge.getChainID(), gomock.Any(), mBridge.blockchain.CurrentHeader().Hash()).Return(p2p.ErrPipeClosed).Times(1) 312 313 err := mBridge.handle(mockBridgePeer) 314 assert.Equal(t, p2p.ErrPipeClosed, err) 315 } 316 // Resolve the above failure condition by making handshake success 317 mockBridgePeer.EXPECT().Handshake(mBridge.networkId, mBridge.getChainID(), gomock.Any(), mBridge.blockchain.CurrentHeader().Hash()).Return(nil).AnyTimes() 318 319 // Case 3 - Error when the same peer was registered before 320 { 321 // Pre-register a peer which will be added again 322 mBridge.peers.peers[bridgePeerID] = &baseBridgePeer{} 323 324 err := mBridge.handle(mockBridgePeer) 325 assert.Equal(t, errAlreadyRegistered, err) 326 } 327 // Resolve the above failure condition by deleting the registered peer 328 delete(mBridge.peers.peers, bridgePeerID) 329 330 // Case 4 - Error if `mBridge.handleMsg` failed 331 { 332 // Close of the peer's pipe make `mBridge.handleMsg` fail 333 _ = pipe.Close() 334 335 err := mBridge.handle(mockBridgePeer) 336 assert.Equal(t, p2p.ErrPipeClosed, err) 337 } 338 } 339 340 // TestMainBridge_SendRPCResponseData tests SendRPCResponseData function of MainBridge. 341 // The function sends RPC response data to MainBridge's peers. 342 func TestMainBridge_SendRPCResponseData(t *testing.T) { 343 // Create a MainBridge 344 mBridge := testNewMainBridge(t) 345 defer mBridge.chainDB.Close() 346 347 // Test data used as a parameter of SendResponseRPC function 348 data := []byte{0x11, 0x22, 0x33} 349 350 // mockBridgePeer mocks BridgePeer 351 mockCtrl := gomock.NewController(t) 352 defer mockCtrl.Finish() 353 354 mockBridgePeer := NewMockBridgePeer(mockCtrl) 355 mockBridgePeer.EXPECT().GetID().Return("testID").AnyTimes() // for `mBridge.BridgePeerSet().Register(mockBridgePeer)` 356 357 // Register mockBridgePeer as a peer of `mBridge.BridgePeerSet` 358 if err := mBridge.BridgePeerSet().Register(mockBridgePeer); err != nil { 359 t.Fatal(err) 360 } 361 362 // Case 1 - Error if SendResponseRPC of mockBridgePeer failed 363 { 364 // Make mockBridgePeer return an error 365 mockBridgePeer.EXPECT().SendResponseRPC(data).Return(p2p.ErrPipeClosed).Times(1) 366 367 err := mBridge.SendRPCResponseData(data) 368 assert.Equal(t, p2p.ErrPipeClosed, err) 369 } 370 371 // Case 2 - Success if SendResponseRPC of mockBridgePeer succeeded 372 { 373 // Make mockBridgePeer return nil 374 mockBridgePeer.EXPECT().SendResponseRPC(data).Return(nil).Times(1) 375 376 err := mBridge.SendRPCResponseData(data) 377 assert.Equal(t, nil, err) 378 } 379 }