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