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 }