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

     1  // Copyright (c) 2020 IoTeX
     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  	"time"
    12  
    13  	"github.com/golang/mock/gomock"
    14  	"github.com/iotexproject/go-pkgs/hash"
    15  	"github.com/iotexproject/iotex-address/address"
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	"github.com/iotexproject/iotex-core/action/protocol"
    20  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    21  	"github.com/iotexproject/iotex-core/consensus/consensusfsm"
    22  	"github.com/iotexproject/iotex-core/state"
    23  	"github.com/iotexproject/iotex-core/test/identityset"
    24  	"github.com/iotexproject/iotex-core/testutil/testdb"
    25  )
    26  
    27  const (
    28  	_stateDBPath = "stateDB.test"
    29  )
    30  
    31  func TestGetPutStaking(t *testing.T) {
    32  	require := require.New(t)
    33  
    34  	ctrl := gomock.NewController(t)
    35  	sm := testdb.NewMockStateManager(ctrl)
    36  	csm := newCandidateStateManager(sm)
    37  	csr := newCandidateStateReader(sm)
    38  	sm.PutState(
    39  		&totalBucketCount{count: 0},
    40  		protocol.NamespaceOption(_stakingNameSpace),
    41  		protocol.KeyOption(TotalBucketKey),
    42  	)
    43  
    44  	tests := []struct {
    45  		name  hash.Hash160
    46  		index uint64
    47  	}{
    48  		{
    49  			hash.BytesToHash160([]byte{1, 2, 3, 4}),
    50  			0,
    51  		},
    52  		{
    53  			hash.BytesToHash160([]byte{1, 2, 3, 4}),
    54  			1,
    55  		},
    56  		{
    57  			hash.BytesToHash160([]byte{2, 3, 4, 5}),
    58  			2,
    59  		},
    60  		{
    61  			hash.BytesToHash160([]byte{2, 3, 4, 5}),
    62  			3,
    63  		},
    64  	}
    65  
    66  	// put buckets and get
    67  	for _, e := range tests {
    68  		addr, _ := address.FromBytes(e.name[:])
    69  		_, err := csr.getBucket(e.index)
    70  		require.Equal(state.ErrStateNotExist, errors.Cause(err))
    71  
    72  		vb := NewVoteBucket(addr, identityset.Address(1), big.NewInt(2100000000), 21*uint32(e.index+1), time.Now(), true)
    73  
    74  		count, err := csr.getTotalBucketCount()
    75  		require.NoError(err)
    76  		require.Equal(e.index, count)
    77  		count, err = csm.putBucket(vb)
    78  		require.NoError(err)
    79  		require.Equal(e.index, count)
    80  		count, err = csr.getTotalBucketCount()
    81  		require.NoError(err)
    82  		require.Equal(e.index+1, count)
    83  		vb1, err := csr.getBucket(e.index)
    84  		require.NoError(err)
    85  		require.Equal(e.index, vb1.Index)
    86  		require.Equal(vb, vb1)
    87  	}
    88  
    89  	vb, err := csr.getBucket(2)
    90  	require.NoError(err)
    91  	vb.AutoStake = false
    92  	vb.StakedAmount.Sub(vb.StakedAmount, big.NewInt(100))
    93  	vb.UnstakeStartTime = time.Now().UTC()
    94  	require.True(vb.isUnstaked())
    95  	require.NoError(csm.updateBucket(2, vb))
    96  	vb1, err := csr.getBucket(2)
    97  	require.NoError(err)
    98  	require.Equal(vb, vb1)
    99  
   100  	// delete buckets and get
   101  	for _, e := range tests {
   102  		require.NoError(csm.delBucket(e.index))
   103  		_, err := csr.getBucket(e.index)
   104  		require.Equal(state.ErrStateNotExist, errors.Cause(err))
   105  	}
   106  }
   107  
   108  func TestCalculateVoteWeight(t *testing.T) {
   109  	// Define test cases
   110  	blockInterval := consensusfsm.DefaultDardanellesUpgradeConfig.BlockInterval
   111  	consts := genesis.Default.VoteWeightCalConsts
   112  	tests := []struct {
   113  		name       string
   114  		consts     genesis.VoteWeightCalConsts
   115  		voteBucket *VoteBucket
   116  		selfStake  bool
   117  		expected   *big.Int
   118  	}{
   119  		{
   120  			name:   "Native, auto-stake enabled, self-stake enabled",
   121  			consts: consts,
   122  			voteBucket: &VoteBucket{
   123  				StakedDuration: time.Duration(100) * 24 * time.Hour,
   124  				AutoStake:      true,
   125  				StakedAmount:   big.NewInt(100),
   126  			},
   127  			selfStake: true,
   128  			expected:  big.NewInt(136),
   129  		},
   130  		{
   131  			name:   "Native, auto-stake enabled, self-stake disabled",
   132  			consts: consts,
   133  			voteBucket: &VoteBucket{
   134  				StakedDuration: time.Duration(100) * 24 * time.Hour,
   135  				AutoStake:      true,
   136  				StakedAmount:   big.NewInt(100),
   137  			},
   138  			selfStake: false,
   139  			expected:  big.NewInt(129),
   140  		},
   141  		{
   142  			name:   "Native, auto-stake disabled, self-stake enabled",
   143  			consts: consts,
   144  			voteBucket: &VoteBucket{
   145  				StakedDuration: time.Duration(100) * 24 * time.Hour,
   146  				AutoStake:      false,
   147  				StakedAmount:   big.NewInt(100),
   148  			},
   149  			selfStake: true,
   150  			expected:  big.NewInt(125),
   151  		},
   152  		{
   153  			name:   "Native, auto-stake disabled, self-stake disabled",
   154  			consts: consts,
   155  			voteBucket: &VoteBucket{
   156  				StakedDuration: time.Duration(100) * 24 * time.Hour,
   157  				AutoStake:      false,
   158  				StakedAmount:   big.NewInt(100),
   159  			},
   160  			selfStake: false,
   161  			expected:  big.NewInt(125),
   162  		},
   163  		{
   164  			name:   "NFT, auto-stake enabled",
   165  			consts: consts,
   166  			voteBucket: &VoteBucket{
   167  				StakedDuration:            30 * 17280 * blockInterval,
   168  				StakedDurationBlockNumber: 30 * 17280,
   169  				AutoStake:                 true,
   170  				StakedAmount:              big.NewInt(10000),
   171  				ContractAddress:           identityset.Address(1).String(),
   172  			},
   173  			selfStake: false,
   174  			expected:  big.NewInt(12245),
   175  		},
   176  		{
   177  			name:   "NFT, auto-stake disabled",
   178  			consts: consts,
   179  			voteBucket: &VoteBucket{
   180  				StakedDuration:            30 * 17280 * blockInterval,
   181  				StakedDurationBlockNumber: 30 * 17280,
   182  				AutoStake:                 false,
   183  				StakedAmount:              big.NewInt(10000),
   184  				ContractAddress:           identityset.Address(1).String(),
   185  			},
   186  			selfStake: false,
   187  			expected:  big.NewInt(11865),
   188  		},
   189  		{
   190  			name:   "NFT-I, auto-stake enabled",
   191  			consts: consts,
   192  			voteBucket: &VoteBucket{
   193  				StakedDuration:            91 * 17280 * blockInterval,
   194  				StakedDurationBlockNumber: 91 * 17280,
   195  				AutoStake:                 true,
   196  				StakedAmount:              big.NewInt(10000),
   197  				ContractAddress:           identityset.Address(1).String(),
   198  			},
   199  			selfStake: false,
   200  			expected:  big.NewInt(12854),
   201  		},
   202  		{
   203  			name:   "NFT-I, auto-stake disabled",
   204  			consts: consts,
   205  			voteBucket: &VoteBucket{
   206  				StakedDuration:            91 * 17280 * blockInterval,
   207  				StakedDurationBlockNumber: 91 * 17280,
   208  				AutoStake:                 false,
   209  				StakedAmount:              big.NewInt(10000),
   210  				ContractAddress:           identityset.Address(1).String(),
   211  			},
   212  			selfStake: true,
   213  			expected:  big.NewInt(12474),
   214  		},
   215  		{
   216  			name:   "NFT-II, auto-stake enabled",
   217  			consts: consts,
   218  			voteBucket: &VoteBucket{
   219  				StakedDuration:            91 * 17280 * blockInterval,
   220  				StakedDurationBlockNumber: 91 * 17280,
   221  				AutoStake:                 true,
   222  				StakedAmount:              big.NewInt(100000),
   223  				ContractAddress:           identityset.Address(1).String(),
   224  			},
   225  			selfStake: false,
   226  			expected:  big.NewInt(128543),
   227  		},
   228  		{
   229  			name:   "NFT-II, auto-stake disabled",
   230  			consts: consts,
   231  			voteBucket: &VoteBucket{
   232  				StakedDuration:            91 * 17280 * blockInterval,
   233  				StakedDurationBlockNumber: 91 * 17280,
   234  				AutoStake:                 false,
   235  				StakedAmount:              big.NewInt(100000),
   236  				ContractAddress:           identityset.Address(1).String(),
   237  			},
   238  			selfStake: true,
   239  			expected:  big.NewInt(124741),
   240  		},
   241  		{
   242  			name:   "NFT-III, auto-stake enabled",
   243  			consts: consts,
   244  			voteBucket: &VoteBucket{
   245  				StakedDuration:            2 * 17280 * blockInterval,
   246  				StakedDurationBlockNumber: 2 * 17280,
   247  				AutoStake:                 true,
   248  				StakedAmount:              big.NewInt(1000),
   249  				ContractAddress:           identityset.Address(1).String(),
   250  			},
   251  			selfStake: false,
   252  			expected:  big.NewInt(1076),
   253  		},
   254  		{
   255  			name:   "NFT-III, auto-stake disabled",
   256  			consts: consts,
   257  			voteBucket: &VoteBucket{
   258  				StakedDuration:            2 * 17280 * blockInterval,
   259  				StakedDurationBlockNumber: 2 * 17280,
   260  				AutoStake:                 false,
   261  				StakedAmount:              big.NewInt(1000),
   262  				ContractAddress:           identityset.Address(1).String(),
   263  			},
   264  			selfStake: true,
   265  			expected:  big.NewInt(1038),
   266  		},
   267  	}
   268  
   269  	// Run tests
   270  	for _, tt := range tests {
   271  		t.Run(tt.name, func(t *testing.T) {
   272  			actual := CalculateVoteWeight(tt.consts, tt.voteBucket, tt.selfStake)
   273  			require.Equal(t, tt.expected, actual)
   274  		})
   275  	}
   276  }
   277  func TestIsUnstaked(t *testing.T) {
   278  	r := require.New(t)
   279  
   280  	// Test for native vote bucket
   281  	vb := NewVoteBucket(identityset.Address(1), identityset.Address(2), big.NewInt(10), 1, time.Now(), false)
   282  	r.False(vb.isUnstaked())
   283  	vb.UnstakeStartTime = vb.StakeStartTime.Add(1 * time.Hour)
   284  	r.True(vb.isUnstaked())
   285  
   286  	// Test for nft vote bucket
   287  	vb = NewVoteBucket(identityset.Address(1), identityset.Address(2), big.NewInt(10), 1, time.Now(), false)
   288  	vb.ContractAddress = identityset.Address(1).String()
   289  	vb.CreateBlockHeight = 1
   290  	vb.StakeStartBlockHeight = 1
   291  	vb.UnstakeStartBlockHeight = maxBlockNumber
   292  	r.False(vb.isUnstaked())
   293  	vb.UnstakeStartBlockHeight = 2
   294  	r.True(vb.isUnstaked())
   295  }