github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/core/vm/election/reward_test.go (about)

     1  // Copyright 2019 The go-vnt Authors
     2  // This file is part of the go-vnt library.
     3  //
     4  // The go-vnt library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-vnt library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package election
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"testing"
    23  
    24  	"github.com/magiconair/properties/assert"
    25  	"github.com/vntchain/go-vnt/common"
    26  )
    27  
    28  type grantCase struct {
    29  	name          string                      // case名称
    30  	balance       *big.Int                    // 合约余额
    31  	allLockBalance *big.Int                    // 锁仓和抵押总额
    32  	cans          CandidateList               // 当前的候选人列表
    33  	rewards       map[common.Address]*big.Int // 待发放余额
    34  	errExpOfGrant error                       // 有error时意味着回滚,也要匹配具体error
    35  	matchTotal    bool                        // 匹配总金额的变化,只有当全部分配或全部未分配时才使用
    36  	// 匹配每个受益账号增加的金额与rewardBalance是否匹配,只有rewards中所有Active受益人能收到激励的测试场景才设置为true
    37  	matchBeneficiary bool
    38  }
    39  
    40  func TestGrantBounty(t *testing.T) {
    41  	be := beneficiary.String()
    42  	be = be[:len(be)-1]
    43  	// binder地址实际不使用,可以相同,Beneficiary地址不能相同
    44  	ca1 := Candidate{Owner: addr1, Binder: binder, Beneficiary: common.HexToAddress(be + "1"), Registered: true, Bind: true}
    45  	ca2 := Candidate{Owner: addr2, Binder: binder, Beneficiary: common.HexToAddress(be + "2"), Registered: true, Bind: true}
    46  	ca3 := Candidate{Owner: addr3, Binder: binder, Beneficiary: common.HexToAddress(be + "3"), Registered: true, Bind: false}
    47  
    48  	// 	用例1:有充足余额,有充足剩余激励,余额减少,收益人余额增加
    49  	{
    50  		caList := CandidateList{ca1, ca2}
    51  		rewards := map[common.Address]*big.Int{
    52  			ca1.Owner: vnt2wei(1),                                     // 1VNT
    53  			ca2.Owner: big.NewInt(0).Div(vnt2wei(15), big.NewInt(10))} // 1.5VNT
    54  		cas := grantCase{"case1", vnt2wei(100), vnt2wei(90), caList, rewards, nil, true, true}
    55  		testGrantBounty(t, &cas)
    56  	}
    57  
    58  	// 	用例2:有充足余额,剩余激励够1个账号的,不足2个账号,有账号的受益人余额增加,有的未增加,剩余激励为0
    59  	{
    60  		caList := CandidateList{ca1, ca2}
    61  		rewards := map[common.Address]*big.Int{
    62  			ca1.Owner: vnt2wei(10), // 10VNT
    63  			ca2.Owner: vnt2wei(20)} // 20VNT
    64  		cas := grantCase{"case2", vnt2wei(100), vnt2wei(75), caList, rewards, nil, false, false}
    65  		testGrantBounty(t, &cas)
    66  	}
    67  
    68  	// 	用例3:有充足余额,有充足剩余激励,候选人有1个未激活,被跳过,检查剩余激励正确
    69  	{
    70  		caList := CandidateList{ca1, ca2, ca3}
    71  		rewards := map[common.Address]*big.Int{
    72  			ca1.Owner: vnt2wei(10), // 10VNT
    73  			ca2.Owner: vnt2wei(20), // 20VNT
    74  			ca3.Owner: vnt2wei(20)} // 20VNT,非法情况,正常调用不会存在非Active的候选人分激励
    75  		cas := grantCase{"case3", vnt2wei(100), vnt2wei(50), caList, rewards, nil, false, true}
    76  		testGrantBounty(t, &cas)
    77  	}
    78  }
    79  
    80  func testGrantBounty(t *testing.T, cas *grantCase) {
    81  	ec := newTestElectionCtx()
    82  	db := ec.context.GetStateDb()
    83  
    84  	// 设置余额
    85  	db.AddBalance(contractAddr, cas.balance)
    86  
    87  	// 设置alllock amount
    88  	err := setLock(db, AllLock{cas.allLockBalance})
    89  	assert.Equal(t, err, nil, fmt.Sprintf("%v, set alllock amount error: %v", cas.name, err))
    90  
    91  	restReward := QueryRestReward(db, big.NewInt(ElectionStart + 1))
    92  	expRestReward := common.Big0
    93  	if cas.balance.Cmp(cas.allLockBalance) > 0 {
    94  		expRestReward = big.NewInt(0).Sub(cas.balance, cas.allLockBalance)
    95  	}
    96  	assert.Equal(t, restReward, expRestReward, fmt.Sprintf("%v, rest bounty amount error: %v", cas.name, err))
    97  
    98  
    99  	// 设置候选人
   100  	for i, can := range cas.cans {
   101  		err = ec.setCandidate(can)
   102  		assert.Equal(t, err, nil, fmt.Sprintf("%v, [%d] set candidate error: %v", cas.name, i, err))
   103  	}
   104  
   105  	// 执行分激励
   106  	err = GrantReward(db, cas.rewards, big.NewInt(ElectionStart + 1))
   107  	assert.Equal(t, err, cas.errExpOfGrant, fmt.Sprintf("%v, grant bounty error mismatch", cas.name))
   108  
   109  	// 校验回滚
   110  	if cas.errExpOfGrant != nil {
   111  		// 校验余额,应当不变
   112  		assert.Equal(t, db.GetBalance(contractAddr), cas.balance, ",", cas.name, ", reverted, balance of contract should not change")
   113  		// 校验剩余激励,应当不变
   114  		acLockAmount, _ := getLock(db)
   115  		assert.Equal(t, acLockAmount.Amount, cas.allLockBalance, ",", cas.name, ", reverted, left reward should not change")
   116  		// 	各候选人账号的收益账号应当为0
   117  		for addr, _ := range cas.rewards {
   118  			can := ec.getCandidate(addr)
   119  			assert.Equal(t, db.GetBalance(can.Beneficiary), common.Big0, ",", cas.name, ", reverted, balance of beneficiary should be 0")
   120  		}
   121  	}
   122  
   123  	// 校验余额和受益人余额增加额是否匹配,剩余激励是否匹配
   124  	totalReward := big.NewInt(0)
   125  	for _, re := range cas.rewards {
   126  		totalReward = totalReward.Add(totalReward, re)
   127  	}
   128  
   129  	reminReward := QueryRestReward(db, big.NewInt(ElectionStart + 1))
   130  	reducedBalance := big.NewInt(0).Sub(cas.balance, db.GetBalance(contractAddr))
   131  	reducedReward := big.NewInt(0).Sub(restReward, reminReward)
   132  	assert.Equal(t, reducedBalance, reducedReward, ",", cas.name, "reduced balance should always equal to reduces reward")
   133  	if cas.matchTotal {
   134  		assert.Equal(t, reducedBalance, totalReward, ",", cas.name, "reduced contract balance should equal total reward")
   135  		assert.Equal(t, reducedReward, totalReward, ",", cas.name, "reduced contract reward should equal total reward")
   136  	}
   137  
   138  	// 	校验每个受益账户增加的余额
   139  	if cas.matchBeneficiary {
   140  		// 统计受益账户应收到的总激励
   141  		benes := make(map[common.Address]*big.Int)
   142  		for addr, amount := range cas.rewards {
   143  			can := ec.getCandidate(addr)
   144  			assert.Equal(t, can.Owner, addr, "%v, candidate address not match", cas.name)
   145  			if can.Active() {
   146  				if _, ok := benes[can.Beneficiary]; ok {
   147  					benes[can.Beneficiary] = big.NewInt(0).Add(benes[can.Beneficiary], amount)
   148  				} else {
   149  					benes[can.Beneficiary] = big.NewInt(0).Set(amount)
   150  				}
   151  			}
   152  		}
   153  
   154  		// 	匹配实际收到金额
   155  		for addr, reward := range benes {
   156  			// 所有受益账户初始都没有余额
   157  			addedBal := db.GetBalance(addr)
   158  			assert.Equal(t, addedBal, reward, fmt.Sprintf("%v, beneficiary reward mismtach: %v", cas.name, addr.String()))
   159  		}
   160  	}
   161  }
   162  
   163  func TestDepositReward(t *testing.T) {
   164  	ec := newTestElectionCtx()
   165  	sender := common.HexToAddress("0x123456")
   166  
   167  	// 初始值应当为0
   168  	got, _:= getLock(ec.context.GetStateDb())
   169  	assert.Equal(t, got.Amount, common.Big0, "rest reward should be 0 at first")
   170  
   171  	// 存负值
   172  	amount := vnt2wei(-1000)
   173  	err := ec.depositReward(sender, amount)
   174  	assert.Equal(t, err, fmt.Errorf("deposit reward less than 0 VNT"), fmt.Sprintf("deposit reward error: %v", err))
   175  
   176  	// 得1000VNT
   177  	amount = vnt2wei(1000)
   178  	err = ec.depositReward(sender, amount)
   179  	assert.Equal(t, err, nil, fmt.Sprintf("deposit reward error: %v", err))
   180  	got, _ = getLock(ec.context.GetStateDb())
   181  	assert.Equal(t, got.Amount, common.Big0, "deposit reward not equal")
   182  }