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  }