github.com/aergoio/aergo@v1.3.1/contract/system/vote_test.go (about) 1 /** 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package system 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "math" 12 "math/big" 13 "os" 14 "strconv" 15 "testing" 16 17 "github.com/aergoio/aergo-lib/db" 18 "github.com/aergoio/aergo/state" 19 "github.com/aergoio/aergo/types" 20 "github.com/libp2p/go-libp2p-core/crypto" 21 "github.com/mr-tron/base58" 22 "github.com/stretchr/testify/assert" 23 ) 24 25 var cdb *state.ChainStateDB 26 var sdb *state.StateDB 27 28 func initTest(t *testing.T) (*state.ContractState, *state.V, *state.V) { 29 cdb = state.NewChainStateDB() 30 cdb.Init(string(db.BadgerImpl), "test", nil, false) 31 genesis := types.GetTestGenesis() 32 sdb = cdb.OpenNewStateDB(cdb.GetRoot()) 33 err := cdb.SetGenesis(genesis, nil) 34 if err != nil { 35 t.Fatalf("failed init : %s", err.Error()) 36 } 37 // Need to pass the 38 InitGovernance("dpos") 39 40 const testSender = "AmPNYHyzyh9zweLwDyuoiUuTVCdrdksxkRWDjVJS76WQLExa2Jr4" 41 42 scs, err := cdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte("aergo.system"))) 43 assert.NoError(t, err, "could not open contract state") 44 45 account, err := types.DecodeAddress(testSender) 46 assert.NoError(t, err, "could not decode test address") 47 sender, err := sdb.GetAccountStateV(account) 48 assert.NoError(t, err, "could not get test address state") 49 receiver, err := sdb.GetAccountStateV([]byte(types.AergoSystem)) 50 assert.NoError(t, err, "could not get test address state") 51 return scs, sender, receiver 52 } 53 54 func deinitTest() { 55 cdb.Close() 56 os.RemoveAll("test") 57 } 58 59 func TestVoteResult(t *testing.T) { 60 const testSize = 64 61 initTest(t) 62 defer deinitTest() 63 scs, err := cdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte("testUpdateVoteResult"))) 64 assert.NoError(t, err, "could not open contract state") 65 testResult := map[string]*big.Int{} 66 for i := 0; i < testSize; i++ { 67 to := fmt.Sprintf("%39d", i) //39:peer id length 68 testResult[base58.Encode([]byte(to))] = new(big.Int).SetUint64(uint64(i * i)) 69 } 70 err = InitVoteResult(scs, nil) 71 assert.NotNil(t, err, "argument should not be nil") 72 err = InitVoteResult(scs, testResult) 73 assert.NoError(t, err, "failed to InitVoteResult") 74 75 result, err := getVoteResult(scs, defaultVoteKey, 23) 76 assert.NoError(t, err, "could not get vote result") 77 78 oldAmount := new(big.Int).SetUint64((uint64)(math.MaxUint64)) 79 for i, v := range result.Votes { 80 oldi := testSize - (i + 1) 81 assert.Falsef(t, new(big.Int).SetBytes(v.Amount).Cmp(oldAmount) > 0, 82 "failed to sort result old:%v, %d:%v", oldAmount, i, new(big.Int).SetBytes(v.Amount)) 83 assert.Equalf(t, uint64(oldi*oldi), new(big.Int).SetBytes(v.Amount).Uint64(), "not match amount value") 84 oldAmount = new(big.Int).SetBytes(v.Amount) 85 } 86 } 87 88 func TestVoteData(t *testing.T) { 89 const testSize = 64 90 initTest(t) 91 defer deinitTest() 92 scs, err := cdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte("testSetGetVoteDate"))) 93 assert.NoError(t, err, "could not open contract state") 94 95 for i := 0; i < testSize; i++ { 96 from := fmt.Sprintf("from%d", i) 97 to := fmt.Sprintf("%39d", i) 98 vote, err := GetVote(scs, []byte(from), defaultVoteKey) 99 assert.NoError(t, err, "failed to getVote") 100 assert.Zero(t, vote.Amount, "new amount value is already set") 101 assert.Nil(t, vote.Candidate, "new candidates value is already set") 102 103 testVote := &types.Vote{Candidate: []byte(to), 104 Amount: new(big.Int).SetUint64(uint64(math.MaxInt64 + i)).Bytes()} 105 106 err = setVote(scs, defaultVoteKey, []byte(from), testVote) 107 assert.NoError(t, err, "failed to setVote") 108 109 vote, err = GetVote(scs, []byte(from), defaultVoteKey) 110 assert.NoError(t, err, "failed to getVote after set") 111 assert.Equal(t, uint64(math.MaxInt64+i), new(big.Int).SetBytes(vote.Amount).Uint64(), "invalid amount") 112 assert.Equal(t, []byte(to), vote.Candidate, "invalid candidates") 113 } 114 } 115 116 func TestBasicStakingVotingUnstaking(t *testing.T) { 117 scs, sender, receiver := initTest(t) 118 defer deinitTest() 119 120 sender.AddBalance(types.MaxAER) 121 tx := &types.Tx{ 122 Body: &types.TxBody{ 123 Account: sender.ID(), 124 Amount: types.StakingMinimum.Bytes(), 125 }, 126 } 127 128 tx.Body.Payload = buildStakingPayload(true) 129 130 context, err := ValidateSystemTx(tx.Body.Account, tx.Body, sender, scs, 0) 131 assert.NoError(t, err, "staking validation") 132 _, err = staking(tx.Body, sender, receiver, scs, 0, context) 133 assert.NoError(t, err, "staking failed") 134 assert.Equal(t, sender.Balance().Bytes(), new(big.Int).Sub(types.MaxAER, types.StakingMinimum).Bytes(), 135 "sender.Balance() should be reduced after staking") 136 137 tx.Body.Payload = buildVotingPayload(1) 138 context, err = ValidateSystemTx(tx.Body.Account, tx.Body, sender, scs, VotingDelay) 139 assert.NoError(t, err, "voting failed") 140 _, err = voting(tx.Body, sender, receiver, scs, VotingDelay, context) 141 assert.NoError(t, err, "voting failed") 142 143 result, err := getVoteResult(scs, defaultVoteKey, 23) 144 assert.NoError(t, err, "voting failed") 145 assert.EqualValues(t, len(result.GetVotes()), 1, "invalid voting result") 146 assert.Equal(t, context.Call.Args[0].(string), base58.Encode(result.GetVotes()[0].Candidate), "invalid candidate in voting result") 147 assert.Equal(t, types.StakingMinimum.Bytes(), result.GetVotes()[0].Amount, "invalid amount in voting result") 148 149 tx.Body.Payload = buildStakingPayload(false) 150 _, err = ExecuteSystemTx(scs, tx.Body, sender, receiver, VotingDelay) 151 assert.EqualError(t, err, types.ErrLessTimeHasPassed.Error(), "unstaking failed") 152 153 context, err = ValidateSystemTx(tx.Body.Account, tx.Body, sender, scs, VotingDelay+StakingDelay) 154 assert.NoError(t, err, "unstaking failed") 155 _, err = unstaking(tx.Body, sender, receiver, scs, VotingDelay+StakingDelay, context) 156 assert.NoError(t, err, "unstaking failed") 157 158 result2, err := getVoteResult(scs, defaultVoteKey, 23) 159 assert.NoError(t, err, "voting failed") 160 assert.EqualValues(t, len(result2.GetVotes()), 1, "invalid voting result") 161 assert.Equal(t, result.GetVotes()[0].Candidate, result2.GetVotes()[0].Candidate, "invalid candidate in voting result") 162 assert.Equal(t, []byte{}, result2.GetVotes()[0].Amount, "invalid candidate in voting result") 163 } 164 165 /* 166 func TestBasicStakeVoteExUnstake(t *testing.T) { 167 initTest(t) 168 defer deinitTest() 169 const testSender = "AmPNYHyzyh9zweLwDyuoiUuTVCdrdksxkRWDjVJS76WQLExa2Jr4" 170 171 scs, err := cdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte("aergo.system"))) 172 assert.NoError(t, err, "could not open contract state") 173 174 account, err := types.DecodeAddress(testSender) 175 assert.NoError(t, err, "could not decode test address") 176 177 tx := &types.Tx{ 178 Body: &types.TxBody{ 179 Account: account, 180 Amount: types.StakingMinimum.Bytes(), 181 }, 182 } 183 sender, err := sdb.GetAccountStateV(tx.Body.Account) 184 assert.NoError(t, err, "could not get test address state") 185 receiver, err := sdb.GetAccountStateV(tx.Body.Recipient) 186 assert.NoError(t, err, "could not get test address state") 187 sender.AddBalance(types.MaxAER) 188 189 tx.Body.Payload = buildStakingPayload(true) 190 _, err = staking(tx.Body, sender, receiver, scs, 0) 191 assert.NoError(t, err, "staking failed") 192 assert.Equal(t, sender.Balance().Bytes(), new(big.Int).Sub(types.MaxAER, types.StakingMinimum).Bytes(), 193 "sender.Balance() should be reduced after staking") 194 195 testsize := 1 196 tx.Body.Payload = buildVotingPayloadEx(testsize, types.VoteNumBP) 197 t.Log("payload = ", string(tx.Body.Payload)) 198 ci, err := ValidateSystemTx(tx.Body.Account, tx.Body, sender, scs, VotingDelay) 199 assert.NoError(t, err, "voting failed") 200 event, err := voting(tx.Body, sender, receiver, scs, VotingDelay, ci) 201 assert.NoError(t, err, "voting failed") 202 assert.Equal(t, types.VoteNumBP[2:], event.EventName, "invalid amount in voting result") 203 204 result, err := getVoteResult(scs, []byte(types.VoteNumBP[2:]), 23) 205 assert.NoError(t, err, "voting failed") 206 assert.EqualValues(t, testsize, len(result.GetVotes()), "invalid voting result") 207 //assert.Equal(t, ci.Args[0].(string), base58.Encode(result.GetVotes()[0].Candidate), "invalid candidate in voting result") 208 //assert.Equal(t, types.StakingMinimum.Bytes(), result.GetVotes()[0].Amount, "invalid amount in voting result") 209 210 tx.Body.Payload = buildStakingPayload(false) 211 _, err = ExecuteSystemTx(scs, tx.Body, sender, receiver, VotingDelay) 212 assert.EqualError(t, err, types.ErrLessTimeHasPassed.Error(), "unstaking failed") 213 214 ci, err = ValidateSystemTx(tx.Body.Account, tx.Body, sender, scs, VotingDelay+StakingDelay) 215 assert.NoError(t, err, "unstaking failed") 216 _, err = unstaking(tx.Body, sender, receiver, scs, VotingDelay+StakingDelay, ci) 217 assert.NoError(t, err, "unstaking failed") 218 219 result2, err := getVoteResult(scs, []byte(types.VoteNumBP[2:]), 23) 220 assert.NoError(t, err, "voting failed") 221 assert.EqualValues(t, testsize, len(result2.GetVotes()), "invalid voting result") 222 assert.Equal(t, result.GetVotes()[0].Candidate, result2.GetVotes()[0].Candidate, "invalid candidate in voting result") 223 assert.Equal(t, []byte{}, result2.GetVotes()[0].Amount, "invalid candidate in voting result") 224 225 } 226 */ 227 228 func buildVotingPayload(count int) []byte { 229 var ci types.CallInfo 230 ci.Name = types.VoteBP 231 for i := 0; i < count; i++ { 232 peerID := make([]byte, PeerIDLength) 233 peerID[0] = byte(i) 234 ci.Args = append(ci.Args, base58.Encode(peerID)) 235 } 236 payload, _ := json.Marshal(ci) 237 return payload 238 } 239 240 func buildVotingPayloadEx(count int, name string) []byte { 241 var ci types.CallInfo 242 ci.Name = name 243 switch name { 244 case types.VoteBP: 245 for i := 0; i < count; i++ { 246 _, pub, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) 247 pid, _ := types.IDFromPublicKey(pub) 248 ci.Args = append(ci.Args, types.IDB58Encode(pid)) 249 } 250 case types.VoteNumBP: 251 for i := 12; i < 12+count; i++ { 252 ci.Args = append(ci.Args, strconv.Itoa(i)) 253 } 254 } 255 payload, _ := json.Marshal(ci) 256 return payload 257 } 258 259 func buildStakingPayload(isStaking bool) []byte { 260 if isStaking { 261 return []byte(`{"Name":"v1stake"}`) 262 } 263 return []byte(`{"Name":"v1unstake"}`) 264 }