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