github.com/iotexproject/iotex-core@v1.14.1-rc1/nodeinfo/manager_test.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package nodeinfo
     7  
     8  import (
     9  	"context"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/golang/mock/gomock"
    14  	"github.com/iotexproject/go-pkgs/crypto"
    15  	"github.com/iotexproject/iotex-core/test/mock/mock_nodeinfo"
    16  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    17  	"github.com/libp2p/go-libp2p-core/peer"
    18  	dto "github.com/prometheus/client_model/go"
    19  	"github.com/stretchr/testify/require"
    20  	"google.golang.org/protobuf/proto"
    21  	"google.golang.org/protobuf/types/known/timestamppb"
    22  )
    23  
    24  func getEmptyWhiteList() []string {
    25  	return []string{}
    26  }
    27  
    28  func TestNewDelegateManager(t *testing.T) {
    29  	require := require.New(t)
    30  	ctrl := gomock.NewController(t)
    31  	defer ctrl.Finish()
    32  	privK, err := crypto.GenerateKey()
    33  	require.NoError(err)
    34  
    35  	t.Run("disable_broadcast", func(t *testing.T) {
    36  		hMock := mock_nodeinfo.NewMockchain(ctrl)
    37  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
    38  		cfg := Config{false, 100 * time.Millisecond, 100 * time.Millisecond, 1000}
    39  		dm := NewInfoManager(&cfg, tMock, hMock, privK, getEmptyWhiteList)
    40  		require.NotNil(dm.nodeMap)
    41  		require.Equal(tMock, dm.transmitter)
    42  		require.Equal(hMock, dm.chain)
    43  		require.Equal(privK, dm.privKey)
    44  		tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Times(0)
    45  		hMock.EXPECT().TipHeight().Return(uint64(2)).Times(0)
    46  		err := dm.Start(context.Background())
    47  		require.NoError(err)
    48  		defer dm.Stop(context.Background())
    49  		time.Sleep(time.Second)
    50  	})
    51  
    52  	t.Run("enable_broadcast", func(t *testing.T) {
    53  		hMock := mock_nodeinfo.NewMockchain(ctrl)
    54  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
    55  		cfg := Config{true, 100 * time.Millisecond, 100 * time.Millisecond, 1000}
    56  		dm := NewInfoManager(&cfg, tMock, hMock, privK, getEmptyWhiteList)
    57  		require.NotNil(dm.nodeMap)
    58  		require.Equal(tMock, dm.transmitter)
    59  		require.Equal(hMock, dm.chain)
    60  		require.Equal(privK, dm.privKey)
    61  		tMock.EXPECT().Info().Return(peer.AddrInfo{}, nil).MinTimes(1)
    62  		hMock.EXPECT().TipHeight().Return(uint64(10)).MinTimes(1)
    63  		tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).MinTimes(1)
    64  		err := dm.Start(context.Background())
    65  		require.NoError(err)
    66  		defer dm.Stop(context.Background())
    67  		time.Sleep(time.Second)
    68  	})
    69  	t.Run("delegate_broadcast", func(t *testing.T) {
    70  		hMock := mock_nodeinfo.NewMockchain(ctrl)
    71  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
    72  		cfg := Config{false, 100 * time.Millisecond, 100 * time.Millisecond, 1000}
    73  		dm := NewInfoManager(&cfg, tMock, hMock, privK, func() []string {
    74  			return []string{privK.PublicKey().Address().String()}
    75  		})
    76  		require.NotNil(dm.nodeMap)
    77  		require.Equal(tMock, dm.transmitter)
    78  		require.Equal(hMock, dm.chain)
    79  		require.Equal(privK, dm.privKey)
    80  		tMock.EXPECT().Info().Return(peer.AddrInfo{}, nil).MinTimes(1)
    81  		hMock.EXPECT().TipHeight().Return(uint64(10)).MinTimes(1)
    82  		tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).MinTimes(1)
    83  		err := dm.Start(context.Background())
    84  		require.NoError(err)
    85  		defer dm.Stop(context.Background())
    86  		time.Sleep(time.Second)
    87  	})
    88  }
    89  
    90  func TestDelegateManager_HandleNodeInfo(t *testing.T) {
    91  	ctrl := gomock.NewController(t)
    92  	defer ctrl.Finish()
    93  
    94  	require := require.New(t)
    95  	privKey, err := crypto.GenerateKey()
    96  	require.NoError(err)
    97  
    98  	t.Run("verify_pass", func(t *testing.T) {
    99  		hMock := mock_nodeinfo.NewMockchain(ctrl)
   100  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
   101  		msg := &iotextypes.NodeInfo{
   102  			Info: &iotextypes.NodeInfoCore{
   103  				Version:   "v1.8.0",
   104  				Height:    200,
   105  				Timestamp: timestamppb.Now(),
   106  				Address:   privKey.PublicKey().Address().String(),
   107  			},
   108  		}
   109  		hash := hashNodeInfo(msg.Info)
   110  		msg.Signature, _ = privKey.Sign(hash[:])
   111  		dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey, getEmptyWhiteList)
   112  		dm.HandleNodeInfo(context.Background(), "abc", msg)
   113  		addr := msg.Info.Address
   114  		nodeGot, ok := dm.nodeMap.Get(addr)
   115  		require.True(ok)
   116  		nodeInfo := nodeGot.(Info)
   117  		require.Equal(msg.Info.Height, nodeInfo.Height)
   118  		require.Equal(msg.Info.Version, nodeInfo.Version)
   119  		require.Equal(msg.Info.Timestamp.AsTime().String(), nodeInfo.Timestamp.String())
   120  		require.Equal("abc", nodeInfo.PeerID)
   121  		m := dto.Metric{}
   122  		_nodeInfoHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m)
   123  		require.Equal(msg.Info.Height, uint64(m.Gauge.GetValue()))
   124  	})
   125  
   126  	t.Run("verify_fail", func(t *testing.T) {
   127  		hMock := mock_nodeinfo.NewMockchain(ctrl)
   128  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
   129  		privKey2, _ := crypto.GenerateKey()
   130  		msg := &iotextypes.NodeInfo{
   131  			Info: &iotextypes.NodeInfoCore{
   132  				Version:   "v1.8.0",
   133  				Height:    200,
   134  				Timestamp: timestamppb.Now(),
   135  				Address:   privKey2.PublicKey().Address().String(),
   136  			},
   137  			Signature: []byte("xxxx"),
   138  		}
   139  		dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey, getEmptyWhiteList)
   140  		dm.HandleNodeInfo(context.Background(), "abc", msg)
   141  		addr := msg.Info.Address
   142  		_, ok := dm.nodeMap.Get(addr)
   143  		require.False(ok)
   144  		m := dto.Metric{}
   145  		_nodeInfoHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m)
   146  		require.Equal(uint64(0), uint64(m.Gauge.GetValue()))
   147  	})
   148  }
   149  
   150  func TestDelegateManager_BroadcastNodeInfo(t *testing.T) {
   151  	require := require.New(t)
   152  	ctrl := gomock.NewController(t)
   153  	defer ctrl.Finish()
   154  	privKey, err := crypto.GenerateKey()
   155  	require.NoError(err)
   156  
   157  	t.Run("update_self", func(t *testing.T) {
   158  		hMock := mock_nodeinfo.NewMockchain(ctrl)
   159  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
   160  		dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey, getEmptyWhiteList)
   161  		height := uint64(200)
   162  		peerID, err := peer.IDFromString("12D3KooWF2fns5ZWKbPfx2U1wQDdxoTK2D6HC3ortbSAQYR4BQp4")
   163  		require.NoError(err)
   164  		hMock.EXPECT().TipHeight().Return(height).Times(1)
   165  		tMock.EXPECT().Info().Return(peer.AddrInfo{ID: peerID}, nil).Times(1)
   166  		tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1)
   167  		err = dm.BroadcastNodeInfo(context.Background())
   168  		require.NoError(err)
   169  		addr := privKey.PublicKey().Address().String()
   170  		nodeGot, ok := dm.nodeMap.Get(addr)
   171  		require.True(ok)
   172  		nodeInfo := nodeGot.(Info)
   173  		require.Equal(height, nodeInfo.Height)
   174  		require.Equal(dm.version, nodeInfo.Version)
   175  		require.Equal(addr, nodeInfo.Address)
   176  		require.Equal(peerID.Pretty(), nodeInfo.PeerID)
   177  	})
   178  }
   179  
   180  func TestDelegateManager_HandleNodeInfoRequest(t *testing.T) {
   181  	require := require.New(t)
   182  	ctrl := gomock.NewController(t)
   183  	defer ctrl.Finish()
   184  	privKey, err := crypto.GenerateKey()
   185  	require.NoError(err)
   186  
   187  	t.Run("unicast", func(t *testing.T) {
   188  		hMock := mock_nodeinfo.NewMockchain(ctrl)
   189  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
   190  		dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey, getEmptyWhiteList)
   191  		height := uint64(200)
   192  		var sig []byte
   193  		message := &iotextypes.NodeInfo{}
   194  		hMock.EXPECT().TipHeight().Return(height).Times(1)
   195  		tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error {
   196  			message = msg.(*iotextypes.NodeInfo)
   197  			hash := hashNodeInfo(message.Info)
   198  			sig, _ = dm.privKey.Sign(hash[:])
   199  			return nil
   200  		}).Times(1)
   201  		err := dm.HandleNodeInfoRequest(context.Background(), peer.AddrInfo{})
   202  		require.NoError(err)
   203  		require.Equal(message.Info.Height, height)
   204  		require.Equal(message.Info.Version, dm.version)
   205  		require.Equal(message.Info.Address, dm.address)
   206  		require.Equal(message.Signature, sig)
   207  	})
   208  }
   209  
   210  func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) {
   211  	require := require.New(t)
   212  	ctrl := gomock.NewController(t)
   213  	defer ctrl.Finish()
   214  	privKey, err := crypto.GenerateKey()
   215  	require.NoError(err)
   216  
   217  	t.Run("request_single", func(t *testing.T) {
   218  		hMock := mock_nodeinfo.NewMockchain(ctrl)
   219  		tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
   220  		dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey, getEmptyWhiteList)
   221  		var paramPeer peer.AddrInfo
   222  		var paramMsg *iotextypes.NodeInfoRequest
   223  		peerID, err := peer.IDFromString("12D3KooWF2fns5ZWKbPfx2U1wQDdxoTK2D6HC3ortbSAQYR4BQp4")
   224  		require.NoError(err)
   225  		targetPeer := peer.AddrInfo{ID: peerID}
   226  		tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(_ context.Context, p peer.AddrInfo, msg proto.Message) {
   227  			paramPeer = p
   228  			paramMsg = msg.(*iotextypes.NodeInfoRequest)
   229  		}).Times(1)
   230  		dm.RequestSingleNodeInfoAsync(context.Background(), targetPeer)
   231  		require.Equal(targetPeer, paramPeer)
   232  		request := iotextypes.NodeInfoRequest{}
   233  		require.Equal(request.String(), paramMsg.String())
   234  	})
   235  }
   236  
   237  func TestDelegateManager_GetNodeByAddr(t *testing.T) {
   238  	require := require.New(t)
   239  	ctrl := gomock.NewController(t)
   240  	defer ctrl.Finish()
   241  	hMock := mock_nodeinfo.NewMockchain(ctrl)
   242  	tMock := mock_nodeinfo.NewMocktransmitter(ctrl)
   243  	privKey, err := crypto.GenerateKey()
   244  	require.NoError(err)
   245  
   246  	dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey, getEmptyWhiteList)
   247  	dm.updateNode(&Info{Address: "1"})
   248  	dm.updateNode(&Info{Address: "2"})
   249  
   250  	t.Run("exist", func(t *testing.T) {
   251  		info, ok := dm.GetNodeInfo("1")
   252  		require.True(ok)
   253  		require.Equal(Info{Address: "1"}, info)
   254  		info, ok = dm.GetNodeInfo("2")
   255  		require.True(ok)
   256  		require.Equal(Info{Address: "2"}, info)
   257  	})
   258  	t.Run("not_exist", func(t *testing.T) {
   259  		_, ok := dm.GetNodeInfo("3")
   260  		require.False(ok)
   261  	})
   262  
   263  }