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  }