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(&params.ChainConfig{
    69  		ChainID:       big.NewInt(2018),
    70  		UnitPrice:     25000000000,
    71  		DeriveShaImpl: 0,
    72  		Istanbul: &params.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  }