github.com/MetalBlockchain/metalgo@v1.11.9/snow/validators/gvalidators/validator_state_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package gvalidators
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"go.uber.org/mock/gomock"
    14  
    15  	"github.com/MetalBlockchain/metalgo/ids"
    16  	"github.com/MetalBlockchain/metalgo/snow/validators"
    17  	"github.com/MetalBlockchain/metalgo/utils/crypto/bls"
    18  	"github.com/MetalBlockchain/metalgo/vms/rpcchainvm/grpcutils"
    19  
    20  	pb "github.com/MetalBlockchain/metalgo/proto/pb/validatorstate"
    21  )
    22  
    23  var errCustom = errors.New("custom")
    24  
    25  type testState struct {
    26  	client *Client
    27  	server *validators.MockState
    28  }
    29  
    30  func setupState(t testing.TB, ctrl *gomock.Controller) *testState {
    31  	require := require.New(t)
    32  
    33  	t.Helper()
    34  
    35  	state := &testState{
    36  		server: validators.NewMockState(ctrl),
    37  	}
    38  
    39  	listener, err := grpcutils.NewListener()
    40  	require.NoError(err)
    41  	serverCloser := grpcutils.ServerCloser{}
    42  
    43  	server := grpcutils.NewServer()
    44  	pb.RegisterValidatorStateServer(server, NewServer(state.server))
    45  	serverCloser.Add(server)
    46  
    47  	go grpcutils.Serve(listener, server)
    48  
    49  	conn, err := grpcutils.Dial(listener.Addr().String())
    50  	require.NoError(err)
    51  
    52  	state.client = NewClient(pb.NewValidatorStateClient(conn))
    53  
    54  	t.Cleanup(func() {
    55  		serverCloser.Stop()
    56  		_ = conn.Close()
    57  		_ = listener.Close()
    58  	})
    59  
    60  	return state
    61  }
    62  
    63  func TestGetMinimumHeight(t *testing.T) {
    64  	require := require.New(t)
    65  	ctrl := gomock.NewController(t)
    66  
    67  	state := setupState(t, ctrl)
    68  
    69  	// Happy path
    70  	expectedHeight := uint64(1337)
    71  	state.server.EXPECT().GetMinimumHeight(gomock.Any()).Return(expectedHeight, nil)
    72  
    73  	height, err := state.client.GetMinimumHeight(context.Background())
    74  	require.NoError(err)
    75  	require.Equal(expectedHeight, height)
    76  
    77  	// Error path
    78  	state.server.EXPECT().GetMinimumHeight(gomock.Any()).Return(expectedHeight, errCustom)
    79  
    80  	_, err = state.client.GetMinimumHeight(context.Background())
    81  	// TODO: require specific error
    82  	require.Error(err) //nolint:forbidigo // currently returns grpc error
    83  }
    84  
    85  func TestGetCurrentHeight(t *testing.T) {
    86  	require := require.New(t)
    87  	ctrl := gomock.NewController(t)
    88  
    89  	state := setupState(t, ctrl)
    90  
    91  	// Happy path
    92  	expectedHeight := uint64(1337)
    93  	state.server.EXPECT().GetCurrentHeight(gomock.Any()).Return(expectedHeight, nil)
    94  
    95  	height, err := state.client.GetCurrentHeight(context.Background())
    96  	require.NoError(err)
    97  	require.Equal(expectedHeight, height)
    98  
    99  	// Error path
   100  	state.server.EXPECT().GetCurrentHeight(gomock.Any()).Return(expectedHeight, errCustom)
   101  
   102  	_, err = state.client.GetCurrentHeight(context.Background())
   103  	// TODO: require specific error
   104  	require.Error(err) //nolint:forbidigo // currently returns grpc error
   105  }
   106  
   107  func TestGetSubnetID(t *testing.T) {
   108  	require := require.New(t)
   109  	ctrl := gomock.NewController(t)
   110  
   111  	state := setupState(t, ctrl)
   112  
   113  	// Happy path
   114  	chainID := ids.GenerateTestID()
   115  	expectedSubnetID := ids.GenerateTestID()
   116  	state.server.EXPECT().GetSubnetID(gomock.Any(), chainID).Return(expectedSubnetID, nil)
   117  
   118  	subnetID, err := state.client.GetSubnetID(context.Background(), chainID)
   119  	require.NoError(err)
   120  	require.Equal(expectedSubnetID, subnetID)
   121  
   122  	// Error path
   123  	state.server.EXPECT().GetSubnetID(gomock.Any(), chainID).Return(expectedSubnetID, errCustom)
   124  
   125  	_, err = state.client.GetSubnetID(context.Background(), chainID)
   126  	// TODO: require specific error
   127  	require.Error(err) //nolint:forbidigo // currently returns grpc error
   128  }
   129  
   130  func TestGetValidatorSet(t *testing.T) {
   131  	require := require.New(t)
   132  	ctrl := gomock.NewController(t)
   133  
   134  	state := setupState(t, ctrl)
   135  
   136  	// Happy path
   137  	sk0, err := bls.NewSecretKey()
   138  	require.NoError(err)
   139  	vdr0 := &validators.GetValidatorOutput{
   140  		NodeID:    ids.GenerateTestNodeID(),
   141  		PublicKey: bls.PublicFromSecretKey(sk0),
   142  		Weight:    1,
   143  	}
   144  
   145  	sk1, err := bls.NewSecretKey()
   146  	require.NoError(err)
   147  	vdr1 := &validators.GetValidatorOutput{
   148  		NodeID:    ids.GenerateTestNodeID(),
   149  		PublicKey: bls.PublicFromSecretKey(sk1),
   150  		Weight:    2,
   151  	}
   152  
   153  	vdr2 := &validators.GetValidatorOutput{
   154  		NodeID:    ids.GenerateTestNodeID(),
   155  		PublicKey: nil,
   156  		Weight:    3,
   157  	}
   158  
   159  	expectedVdrs := map[ids.NodeID]*validators.GetValidatorOutput{
   160  		vdr0.NodeID: vdr0,
   161  		vdr1.NodeID: vdr1,
   162  		vdr2.NodeID: vdr2,
   163  	}
   164  	height := uint64(1337)
   165  	subnetID := ids.GenerateTestID()
   166  	state.server.EXPECT().GetValidatorSet(gomock.Any(), height, subnetID).Return(expectedVdrs, nil)
   167  
   168  	vdrs, err := state.client.GetValidatorSet(context.Background(), height, subnetID)
   169  	require.NoError(err)
   170  	require.Equal(expectedVdrs, vdrs)
   171  
   172  	// Error path
   173  	state.server.EXPECT().GetValidatorSet(gomock.Any(), height, subnetID).Return(expectedVdrs, errCustom)
   174  
   175  	_, err = state.client.GetValidatorSet(context.Background(), height, subnetID)
   176  	// TODO: require specific error
   177  	require.Error(err) //nolint:forbidigo // currently returns grpc error
   178  }
   179  
   180  func TestPublicKeyDeserialize(t *testing.T) {
   181  	require := require.New(t)
   182  
   183  	sk, err := bls.NewSecretKey()
   184  	require.NoError(err)
   185  	pk := bls.PublicFromSecretKey(sk)
   186  
   187  	pkBytes := bls.PublicKeyToUncompressedBytes(pk)
   188  	pkDe := bls.PublicKeyFromValidUncompressedBytes(pkBytes)
   189  	require.NotNil(pkDe)
   190  	require.Equal(pk, pkDe)
   191  }
   192  
   193  // BenchmarkGetValidatorSet measures the time it takes complete a gRPC client
   194  // request based on a mocked validator set.
   195  func BenchmarkGetValidatorSet(b *testing.B) {
   196  	for _, size := range []int{1, 16, 32, 1024, 2048} {
   197  		vs := setupValidatorSet(b, size)
   198  		b.Run(fmt.Sprintf("get_validator_set_%d_validators", size), func(b *testing.B) {
   199  			benchmarkGetValidatorSet(b, vs)
   200  		})
   201  	}
   202  }
   203  
   204  func benchmarkGetValidatorSet(b *testing.B, vs map[ids.NodeID]*validators.GetValidatorOutput) {
   205  	require := require.New(b)
   206  	ctrl := gomock.NewController(b)
   207  	state := setupState(b, ctrl)
   208  
   209  	height := uint64(1337)
   210  	subnetID := ids.GenerateTestID()
   211  	state.server.EXPECT().GetValidatorSet(gomock.Any(), height, subnetID).Return(vs, nil).AnyTimes()
   212  	b.ResetTimer()
   213  	for i := 0; i < b.N; i++ {
   214  		_, err := state.client.GetValidatorSet(context.Background(), height, subnetID)
   215  		require.NoError(err)
   216  	}
   217  	b.StopTimer()
   218  }
   219  
   220  func setupValidatorSet(b *testing.B, size int) map[ids.NodeID]*validators.GetValidatorOutput {
   221  	b.Helper()
   222  
   223  	set := make(map[ids.NodeID]*validators.GetValidatorOutput, size)
   224  	sk, err := bls.NewSecretKey()
   225  	require.NoError(b, err)
   226  	pk := bls.PublicFromSecretKey(sk)
   227  	for i := 0; i < size; i++ {
   228  		id := ids.GenerateTestNodeID()
   229  		set[id] = &validators.GetValidatorOutput{
   230  			NodeID:    id,
   231  			PublicKey: pk,
   232  			Weight:    uint64(i),
   233  		}
   234  	}
   235  	return set
   236  }