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 }