github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/staking/candidate_test.go (about)

     1  // Copyright (c) 2020 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 staking
     7  
     8  import (
     9  	"math/big"
    10  	"testing"
    11  
    12  	"github.com/golang/mock/gomock"
    13  	"github.com/pkg/errors"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/iotexproject/iotex-core/action"
    17  	"github.com/iotexproject/iotex-core/pkg/unit"
    18  	"github.com/iotexproject/iotex-core/state"
    19  	"github.com/iotexproject/iotex-core/test/identityset"
    20  	"github.com/iotexproject/iotex-core/testutil/testdb"
    21  )
    22  
    23  func TestSer(t *testing.T) {
    24  	r := require.New(t)
    25  
    26  	l := &CandidateList{
    27  		&Candidate{
    28  			Owner:              identityset.Address(1),
    29  			Operator:           identityset.Address(2),
    30  			Reward:             identityset.Address(3),
    31  			Name:               "testname1",
    32  			Votes:              big.NewInt(100),
    33  			SelfStakeBucketIdx: 0,
    34  			SelfStake:          big.NewInt(1100000000),
    35  		},
    36  		&Candidate{
    37  			Owner:              identityset.Address(4),
    38  			Operator:           identityset.Address(5),
    39  			Reward:             identityset.Address(6),
    40  			Name:               "testname2",
    41  			Votes:              big.NewInt(20),
    42  			SelfStakeBucketIdx: 1,
    43  			SelfStake:          big.NewInt(2100000000),
    44  		},
    45  		&Candidate{
    46  			Owner:              identityset.Address(7),
    47  			Operator:           identityset.Address(8),
    48  			Reward:             identityset.Address(9),
    49  			Name:               "testname3",
    50  			Votes:              big.NewInt(3000),
    51  			SelfStakeBucketIdx: 2,
    52  			SelfStake:          big.NewInt(3100000000),
    53  		},
    54  	}
    55  
    56  	ser, err := l.Serialize()
    57  	r.NoError(err)
    58  	l1 := &CandidateList{}
    59  	r.NoError(l1.Deserialize(ser))
    60  	r.Equal(l, l1)
    61  
    62  	// empty CandidateList can successfully Serialize/Deserialize
    63  	var m CandidateList
    64  	ser, err = m.Serialize()
    65  	r.NoError(err)
    66  	r.Equal([]byte{}, ser)
    67  	var m1 CandidateList
    68  	r.NoError(m1.Deserialize(ser))
    69  	r.Nil(m1)
    70  }
    71  
    72  func TestClone(t *testing.T) {
    73  	r := require.New(t)
    74  
    75  	d := &Candidate{
    76  		Owner:              identityset.Address(1),
    77  		Operator:           identityset.Address(2),
    78  		Reward:             identityset.Address(3),
    79  		Name:               "testname1234",
    80  		Votes:              big.NewInt(0),
    81  		SelfStakeBucketIdx: 0,
    82  		SelfStake:          big.NewInt(2100000000),
    83  	}
    84  	r.NoError(d.Validate())
    85  
    86  	d2 := d.Clone()
    87  	r.True(d.Equal(d2))
    88  	d.AddVote(big.NewInt(100))
    89  	r.False(d.Equal(d2))
    90  	r.NoError(d.Collision(d2))
    91  	d.Owner = identityset.Address(0)
    92  	r.Equal(action.ErrInvalidCanName, d.Collision(d2))
    93  	d.Name = "noconflict"
    94  	r.Equal(ErrInvalidOperator, d.Collision(d2))
    95  	d.Operator = identityset.Address(0)
    96  	r.Equal(ErrInvalidSelfStkIndex, d.Collision(d2))
    97  	d.SelfStakeBucketIdx++
    98  	r.NoError(d.Collision(d2))
    99  
   100  	c := d.toStateCandidate()
   101  	r.Equal(d.Owner.String(), c.Address)
   102  	r.Equal(d.Reward.String(), c.RewardAddress)
   103  	r.Equal(d.Votes, c.Votes)
   104  	r.Equal(d.Name, string(c.CanName))
   105  }
   106  
   107  var (
   108  	testCandidates = []struct {
   109  		d     *Candidate
   110  		index int
   111  	}{
   112  		{
   113  			&Candidate{
   114  				Owner:              identityset.Address(1),
   115  				Operator:           identityset.Address(7),
   116  				Reward:             identityset.Address(1),
   117  				Name:               "test1",
   118  				Votes:              big.NewInt(2),
   119  				SelfStakeBucketIdx: 1,
   120  				SelfStake:          unit.ConvertIotxToRau(1200000),
   121  			},
   122  			2,
   123  		},
   124  		{
   125  			&Candidate{
   126  				Owner:              identityset.Address(2),
   127  				Operator:           identityset.Address(8),
   128  				Reward:             identityset.Address(1),
   129  				Name:               "test2",
   130  				Votes:              big.NewInt(3),
   131  				SelfStakeBucketIdx: 2,
   132  				SelfStake:          unit.ConvertIotxToRau(1200000),
   133  			},
   134  			1,
   135  		},
   136  		{
   137  			&Candidate{
   138  				Owner:              identityset.Address(3),
   139  				Operator:           identityset.Address(9),
   140  				Reward:             identityset.Address(1),
   141  				Name:               "test3",
   142  				Votes:              big.NewInt(3),
   143  				SelfStakeBucketIdx: 3,
   144  				SelfStake:          unit.ConvertIotxToRau(1200000),
   145  			},
   146  			0,
   147  		},
   148  		{
   149  			&Candidate{
   150  				Owner:              identityset.Address(4),
   151  				Operator:           identityset.Address(10),
   152  				Reward:             identityset.Address(1),
   153  				Name:               "test4",
   154  				Votes:              big.NewInt(1),
   155  				SelfStakeBucketIdx: 4,
   156  				SelfStake:          unit.ConvertIotxToRau(1200000),
   157  			},
   158  			3,
   159  		},
   160  		// the below 2 will be filtered out in ActiveCandidates() due to insufficient self-stake
   161  		{
   162  			&Candidate{
   163  				Owner:              identityset.Address(5),
   164  				Operator:           identityset.Address(11),
   165  				Reward:             identityset.Address(2),
   166  				Name:               "test5",
   167  				Votes:              big.NewInt(1),
   168  				SelfStakeBucketIdx: 5,
   169  				SelfStake:          unit.ConvertIotxToRau(1199999),
   170  			},
   171  			5,
   172  		},
   173  		{
   174  			&Candidate{
   175  				Owner:              identityset.Address(6),
   176  				Operator:           identityset.Address(12),
   177  				Reward:             identityset.Address(2),
   178  				Name:               "test6",
   179  				Votes:              big.NewInt(1),
   180  				SelfStakeBucketIdx: 0,
   181  				SelfStake:          unit.ConvertIotxToRau(1100000),
   182  			},
   183  			6,
   184  		},
   185  	}
   186  )
   187  
   188  func TestGetPutCandidate(t *testing.T) {
   189  	require := require.New(t)
   190  
   191  	ctrl := gomock.NewController(t)
   192  	sm := testdb.NewMockStateManager(ctrl)
   193  	csm := newCandidateStateManager(sm)
   194  	csr := newCandidateStateReader(sm)
   195  
   196  	// put candidates and get
   197  	for _, e := range testCandidates {
   198  		_, _, err := csr.getCandidate(e.d.Owner)
   199  		require.Equal(state.ErrStateNotExist, errors.Cause(err))
   200  		require.NoError(csm.putCandidate(e.d))
   201  		d1, _, err := csr.getCandidate(e.d.Owner)
   202  		require.NoError(err)
   203  		require.Equal(e.d, d1)
   204  	}
   205  
   206  	// get all candidates
   207  	all, _, err := csr.getAllCandidates()
   208  	require.NoError(err)
   209  	require.Equal(len(testCandidates), len(all))
   210  	for _, e := range testCandidates {
   211  		for i := range all {
   212  			if all[i].Name == e.d.Name {
   213  				require.Equal(e.d, all[i])
   214  				break
   215  			}
   216  		}
   217  	}
   218  
   219  	// delete buckets and get
   220  	for _, e := range testCandidates {
   221  		require.NoError(csm.delCandidate(e.d.Owner))
   222  		_, _, err := csr.getCandidate(e.d.Owner)
   223  		require.Equal(state.ErrStateNotExist, errors.Cause(err))
   224  	}
   225  }
   226  
   227  func TestLess(t *testing.T) {
   228  	r := require.New(t)
   229  	pairs := []CandidateList{
   230  		{
   231  			&Candidate{
   232  				Owner:              identityset.Address(6),
   233  				Operator:           identityset.Address(12),
   234  				Reward:             identityset.Address(2),
   235  				Name:               "test6",
   236  				Votes:              big.NewInt(2),
   237  				SelfStakeBucketIdx: 0,
   238  				SelfStake:          unit.ConvertIotxToRau(1100000),
   239  			},
   240  			&Candidate{
   241  				Owner:              identityset.Address(6),
   242  				Operator:           identityset.Address(12),
   243  				Reward:             identityset.Address(2),
   244  				Name:               "test6",
   245  				Votes:              big.NewInt(1),
   246  				SelfStakeBucketIdx: 0,
   247  				SelfStake:          unit.ConvertIotxToRau(1100000),
   248  			},
   249  		},
   250  		{
   251  			&Candidate{
   252  				Owner:              identityset.Address(6),
   253  				Operator:           identityset.Address(12),
   254  				Reward:             identityset.Address(2),
   255  				Name:               "test6",
   256  				Votes:              big.NewInt(1),
   257  				SelfStakeBucketIdx: 0,
   258  				SelfStake:          unit.ConvertIotxToRau(1100000),
   259  			},
   260  			&Candidate{
   261  				Owner:              identityset.Address(5),
   262  				Operator:           identityset.Address(12),
   263  				Reward:             identityset.Address(2),
   264  				Name:               "test6",
   265  				Votes:              big.NewInt(1),
   266  				SelfStakeBucketIdx: 0,
   267  				SelfStake:          unit.ConvertIotxToRau(1100000),
   268  			},
   269  		},
   270  		{
   271  			&Candidate{
   272  				Owner:              identityset.Address(6),
   273  				Operator:           identityset.Address(6),
   274  				Reward:             identityset.Address(2),
   275  				Name:               "test6",
   276  				Votes:              big.NewInt(1),
   277  				SelfStakeBucketIdx: 0,
   278  				SelfStake:          unit.ConvertIotxToRau(1100000),
   279  			},
   280  			&Candidate{
   281  				Owner:              identityset.Address(6),
   282  				Operator:           identityset.Address(5),
   283  				Reward:             identityset.Address(2),
   284  				Name:               "test6",
   285  				Votes:              big.NewInt(1),
   286  				SelfStakeBucketIdx: 0,
   287  				SelfStake:          unit.ConvertIotxToRau(1100000),
   288  			},
   289  		},
   290  		{
   291  			&Candidate{
   292  				Owner:              identityset.Address(6),
   293  				Operator:           identityset.Address(12),
   294  				Reward:             identityset.Address(6),
   295  				Name:               "test6",
   296  				Votes:              big.NewInt(1),
   297  				SelfStakeBucketIdx: 0,
   298  				SelfStake:          unit.ConvertIotxToRau(1100000),
   299  			},
   300  			&Candidate{
   301  				Owner:              identityset.Address(6),
   302  				Operator:           identityset.Address(12),
   303  				Reward:             identityset.Address(5),
   304  				Name:               "test6",
   305  				Votes:              big.NewInt(1),
   306  				SelfStakeBucketIdx: 0,
   307  				SelfStake:          unit.ConvertIotxToRau(1100000),
   308  			},
   309  		},
   310  		{
   311  			&Candidate{
   312  				Owner:              identityset.Address(6),
   313  				Operator:           identityset.Address(12),
   314  				Reward:             identityset.Address(6),
   315  				Name:               "test6",
   316  				Votes:              big.NewInt(1),
   317  				SelfStakeBucketIdx: 0,
   318  				SelfStake:          unit.ConvertIotxToRau(1100000),
   319  			},
   320  			&Candidate{
   321  				Owner:              identityset.Address(6),
   322  				Operator:           identityset.Address(12),
   323  				Reward:             identityset.Address(6),
   324  				Name:               "test5",
   325  				Votes:              big.NewInt(1),
   326  				SelfStakeBucketIdx: 0,
   327  				SelfStake:          unit.ConvertIotxToRau(1100000),
   328  			},
   329  		},
   330  		{
   331  			&Candidate{
   332  				Owner:              identityset.Address(6),
   333  				Operator:           identityset.Address(12),
   334  				Reward:             identityset.Address(6),
   335  				Name:               "test6",
   336  				Votes:              big.NewInt(1),
   337  				SelfStakeBucketIdx: 1,
   338  				SelfStake:          unit.ConvertIotxToRau(1100000),
   339  			},
   340  			&Candidate{
   341  				Owner:              identityset.Address(6),
   342  				Operator:           identityset.Address(12),
   343  				Reward:             identityset.Address(6),
   344  				Name:               "test6",
   345  				Votes:              big.NewInt(1),
   346  				SelfStakeBucketIdx: 0,
   347  				SelfStake:          unit.ConvertIotxToRau(1100000),
   348  			},
   349  		},
   350  		{
   351  			&Candidate{
   352  				Owner:              identityset.Address(6),
   353  				Operator:           identityset.Address(12),
   354  				Reward:             identityset.Address(6),
   355  				Name:               "test6",
   356  				Votes:              big.NewInt(1),
   357  				SelfStakeBucketIdx: 0,
   358  				SelfStake:          unit.ConvertIotxToRau(1100001),
   359  			},
   360  			&Candidate{
   361  				Owner:              identityset.Address(6),
   362  				Operator:           identityset.Address(12),
   363  				Reward:             identityset.Address(6),
   364  				Name:               "test6",
   365  				Votes:              big.NewInt(1),
   366  				SelfStakeBucketIdx: 0,
   367  				SelfStake:          unit.ConvertIotxToRau(1100000),
   368  			},
   369  		},
   370  	}
   371  	for _, pair := range pairs {
   372  		r.True(pair.Less(0, 1))
   373  	}
   374  }