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