github.com/XinFinOrg/xdcchain@v1.1.0/contracts/validator/validator_test.go (about) 1 // Copyright (c) 2018 XDCchain 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Lesser General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Lesser General Public License for more details. 12 // 13 // You should have received a copy of the GNU Lesser General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package validator 17 18 import ( 19 "context" 20 "encoding/json" 21 "math/big" 22 "math/rand" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/accounts/abi/bind" 27 "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" 28 "github.com/ethereum/go-ethereum/common" 29 contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract" 30 "github.com/ethereum/go-ethereum/core" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/log" 33 ) 34 35 var ( 36 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 37 addr = crypto.PubkeyToAddress(key.PublicKey) 38 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 39 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 40 acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 41 acc4Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a") 42 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 43 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 44 acc3Addr = crypto.PubkeyToAddress(acc3Key.PublicKey) 45 acc4Addr = crypto.PubkeyToAddress(acc4Key.PublicKey) 46 ) 47 48 func TestValidator(t *testing.T) { 49 contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) 50 transactOpts := bind.NewKeyedTransactor(key) 51 52 validatorCap := new(big.Int) 53 validatorCap.SetString("50000000000000000000000", 10) 54 validatorAddress, validator, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr}, []*big.Int{validatorCap}, addr) 55 if err != nil { 56 t.Fatalf("can't deploy root registry: %v", err) 57 } 58 contractBackend.Commit() 59 60 d := time.Now().Add(1000 * time.Millisecond) 61 ctx, cancel := context.WithDeadline(context.Background(), d) 62 defer cancel() 63 code, _ := contractBackend.CodeAt(ctx, validatorAddress, nil) 64 t.Log("contract code", common.ToHex(code)) 65 f := func(key, val common.Hash) bool { 66 t.Log(key.Hex(), val.Hex()) 67 return true 68 } 69 contractBackend.ForEachStorageAt(ctx, validatorAddress, nil, f) 70 71 candidates, err := validator.GetCandidates() 72 if err != nil { 73 t.Fatalf("can't get candidates: %v", err) 74 } 75 for _, it := range candidates { 76 cap, _ := validator.GetCandidateCap(it) 77 t.Log("candidate", it.String(), "cap", cap) 78 owner, _ := validator.GetCandidateOwner(it) 79 t.Log("candidate", it.String(), "validator owner", owner.String()) 80 } 81 contractBackend.Commit() 82 } 83 84 func TestRewardBalance(t *testing.T) { 85 contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{ 86 acc1Addr: {Balance: new(big.Int).SetUint64(10000000)}, 87 acc2Addr: {Balance: new(big.Int).SetUint64(10000000)}, 88 acc4Addr: {Balance: new(big.Int).SetUint64(10000000)}, 89 }, 10000000) 90 acc1Opts := bind.NewKeyedTransactor(acc1Key) 91 acc2Opts := bind.NewKeyedTransactor(acc2Key) 92 accounts := []*bind.TransactOpts{acc1Opts, acc2Opts} 93 transactOpts := bind.NewKeyedTransactor(acc1Key) 94 95 // validatorAddr, _, baseValidator, err := contract.DeployXDCValidator(transactOpts, contractBackend, big.NewInt(50000), big.NewInt(99), big.NewInt(100), big.NewInt(100)) 96 validatorCap := new(big.Int) 97 validatorCap.SetString("50000000000000000000000", 10) 98 validatorAddr, _, baseValidator, err := contractValidator.DeployXDCValidator( 99 transactOpts, 100 contractBackend, 101 []common.Address{addr}, 102 []*big.Int{validatorCap}, 103 addr, 104 big.NewInt(50000), 105 big.NewInt(1), 106 big.NewInt(99), 107 big.NewInt(100), 108 big.NewInt(100), 109 ) 110 if err != nil { 111 t.Fatalf("can't deploy root registry: %v", err) 112 } 113 contractBackend.Commit() 114 115 // Propose master node acc3Addr. 116 opts := bind.NewKeyedTransactor(acc4Key) 117 opts.Value = new(big.Int).SetUint64(50000) 118 acc4Validator, _ := NewValidator(opts, validatorAddr, contractBackend) 119 acc4Validator.Propose(acc3Addr) 120 contractBackend.Commit() 121 122 totalVote := 0 123 type logCap struct { 124 Addr string 125 Balance int 126 } 127 logCaps := make(map[int]*logCap) 128 for i := 0; i <= 10; i++ { 129 rand.Seed(time.Now().UTC().UnixNano()) 130 randIndex := rand.Intn(len(accounts)) 131 randCap := rand.Intn(10) * 1000 132 if randCap <= 0 { 133 randCap = 1000 134 } 135 totalVote += randCap 136 accounts[randIndex].Value = new(big.Int).SetInt64(int64(randCap)) 137 validator, err := NewValidator(accounts[randIndex], validatorAddr, contractBackend) 138 if err != nil { 139 t.Fatalf("can't get current validator: %v", err) 140 } 141 validator.Vote(acc3Addr) 142 contractBackend.Commit() 143 logCaps[i] = &logCap{accounts[randIndex].From.String(), randCap} 144 } 145 146 foundationAddr := common.HexToAddress(common.FoudationAddr) 147 totalReward := new(big.Int).SetInt64(15 * 1000) 148 rewards, err := GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator) 149 if err != nil { 150 t.Error("Fail to get reward balances rate.", err) 151 } 152 153 afterReward := new(big.Int) 154 for _, value := range rewards { 155 afterReward = new(big.Int).Add(afterReward, value) 156 } 157 158 if totalReward.Int64()+5 < afterReward.Int64() || totalReward.Int64()-5 > afterReward.Int64() { 159 callOpts := new(bind.CallOpts) 160 voters, err := baseValidator.GetVoters(callOpts, acc3Addr) 161 if err != nil { 162 t.Fatal("Can not get voters in validator contract.", err) 163 } 164 for addr, capacity := range logCaps { 165 t.Errorf("from %v - %v", addr, capacity) 166 } 167 for _, voter := range voters { 168 voteCap, _ := baseValidator.GetVoterCap(callOpts, acc3Addr, voter) 169 t.Errorf("vote %v - %v", voter.String(), voteCap) 170 } 171 for addr, value := range rewards { 172 t.Errorf("reaward %v - %v", addr.String(), value) 173 } 174 175 t.Errorf("reward total %v - %v", totalReward, afterReward) 176 } 177 178 } 179 180 func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.XDCValidator) (map[common.Address]*big.Int, error) { 181 owner := GetCandidatesOwnerBySigner(validator, masterAddr) 182 balances := make(map[common.Address]*big.Int) 183 rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent)) 184 rewardMaster = new(big.Int).Div(rewardMaster, new(big.Int).SetInt64(100)) 185 balances[owner] = rewardMaster 186 // Get voters for masternode. 187 opts := new(bind.CallOpts) 188 voters, err := validator.GetVoters(opts, masterAddr) 189 if err != nil { 190 log.Crit("Fail to get voters", "error", err) 191 return nil, err 192 } 193 194 if len(voters) > 0 { 195 totalVoterReward := new(big.Int).Mul(totalReward, new(big.Int).SetUint64(common.RewardVoterPercent)) 196 totalVoterReward = new(big.Int).Div(totalVoterReward, new(big.Int).SetUint64(100)) 197 totalCap := new(big.Int) 198 // Get voters capacities. 199 voterCaps := make(map[common.Address]*big.Int) 200 for _, voteAddr := range voters { 201 var voterCap *big.Int 202 203 voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) 204 if err != nil { 205 log.Crit("Fail to get vote capacity", "error", err) 206 } 207 208 totalCap.Add(totalCap, voterCap) 209 voterCaps[voteAddr] = voterCap 210 } 211 if totalCap.Cmp(new(big.Int).SetInt64(0)) > 0 { 212 for addr, voteCap := range voterCaps { 213 // Only valid voter has cap > 0. 214 if voteCap.Cmp(new(big.Int).SetInt64(0)) > 0 { 215 rcap := new(big.Int).Mul(totalVoterReward, voteCap) 216 rcap = new(big.Int).Div(rcap, totalCap) 217 if balances[addr] != nil { 218 balances[addr].Add(balances[addr], rcap) 219 } else { 220 balances[addr] = rcap 221 } 222 } 223 } 224 } 225 } 226 227 foudationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent)) 228 foudationReward = new(big.Int).Div(foudationReward, new(big.Int).SetInt64(100)) 229 balances[foudationWalletAddr] = foudationReward 230 231 jsonHolders, err := json.Marshal(balances) 232 if err != nil { 233 log.Error("Fail to parse json holders", "error", err) 234 return nil, err 235 } 236 log.Info("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String()) 237 238 return balances, nil 239 } 240 241 func GetCandidatesOwnerBySigner(validator *contractValidator.XDCValidator, signerAddr common.Address) common.Address { 242 owner := signerAddr 243 opts := new(bind.CallOpts) 244 owner, err := validator.GetCandidateOwner(opts, signerAddr) 245 if err != nil { 246 log.Error("Fail get candidate owner", "error", err) 247 return owner 248 } 249 250 return owner 251 }