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(&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(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  }