github.com/klaytn/klaytn@v1.12.1/consensus/istanbul/validator/weighted_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package validator
    18  
    19  import (
    20  	"math/big"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/klaytn/klaytn/blockchain"
    26  	"github.com/klaytn/klaytn/common"
    27  	"github.com/klaytn/klaytn/consensus/istanbul"
    28  	"github.com/klaytn/klaytn/crypto"
    29  	"github.com/klaytn/klaytn/fork"
    30  	"github.com/klaytn/klaytn/params"
    31  	"github.com/stretchr/testify/assert"
    32  )
    33  
    34  func TestNewWeightedCouncil(t *testing.T) {
    35  	const ValCnt = 100
    36  	var validators []istanbul.Validator
    37  	var rewardAddrs []common.Address
    38  	var votingPowers []uint64
    39  
    40  	// Create 100 validators with random addresses
    41  	b := []byte{}
    42  	for i := 0; i < ValCnt; i++ {
    43  		key, _ := crypto.GenerateKey()
    44  		addr := crypto.PubkeyToAddress(key.PublicKey)
    45  		val := New(addr)
    46  		validators = append(validators, val)
    47  		b = append(b, val.Address().Bytes()...)
    48  
    49  		rewardKey, _ := crypto.GenerateKey()
    50  		rewardAddr := crypto.PubkeyToAddress(rewardKey.PublicKey)
    51  		rewardAddrs = append(rewardAddrs, rewardAddr)
    52  
    53  		votingPowers = append(votingPowers, uint64(1))
    54  	}
    55  
    56  	// Create ValidatorSet
    57  	valSet := NewWeightedCouncil(ExtractValidators(b), nil, rewardAddrs, votingPowers, nil, istanbul.WeightedRandom, 21, 0, 0, nil)
    58  	if valSet == nil {
    59  		t.Errorf("the validator byte array cannot be parsed")
    60  		t.FailNow()
    61  	}
    62  
    63  	// Check validators sorting: should be in ascending order
    64  	for i := 0; i < ValCnt-1; i++ {
    65  		val := valSet.GetByIndex(uint64(i))
    66  		nextVal := valSet.GetByIndex(uint64(i + 1))
    67  		if strings.Compare(val.String(), nextVal.String()) >= 0 {
    68  			t.Errorf("validator set is not sorted in descending order")
    69  		}
    70  	}
    71  }
    72  
    73  func TestNormalWeightedCouncil(t *testing.T) {
    74  	fork.SetHardForkBlockNumberConfig(&params.ChainConfig{
    75  		IstanbulCompatibleBlock: big.NewInt(5),
    76  	})
    77  	defer fork.ClearHardForkBlockNumberConfig()
    78  
    79  	b1 := common.Hex2Bytes(testAddress)
    80  	b2 := common.Hex2Bytes(testAddress2)
    81  	addr1 := common.BytesToAddress(b1)
    82  	addr2 := common.BytesToAddress(b2)
    83  
    84  	rewardKey1, _ := crypto.GenerateKey()
    85  	rewardAddr1 := crypto.PubkeyToAddress(rewardKey1.PublicKey)
    86  
    87  	rewardKey2, _ := crypto.GenerateKey()
    88  	rewardAddr2 := crypto.PubkeyToAddress(rewardKey2.PublicKey)
    89  
    90  	votingPower1 := uint64(1)
    91  	votingPower2 := uint64(2)
    92  
    93  	weight1 := uint64(1)
    94  	weight2 := uint64(2)
    95  
    96  	val1 := newWeightedValidator(addr1, rewardAddr1, votingPower1, weight1)
    97  	val2 := newWeightedValidator(addr2, rewardAddr2, votingPower2, weight2)
    98  
    99  	valSet := NewWeightedCouncil([]common.Address{addr1, addr2}, nil, []common.Address{rewardAddr1, rewardAddr2}, []uint64{votingPower1, votingPower2}, []uint64{weight1, weight2}, istanbul.WeightedRandom, 21, 0, 0, nil)
   100  	if valSet == nil {
   101  		t.Errorf("the format of validator set is invalid")
   102  		t.FailNow()
   103  	}
   104  
   105  	// check size
   106  	if size := valSet.Size(); size != 2 {
   107  		t.Errorf("the size of validator set is wrong: have %v, want 2", size)
   108  	}
   109  
   110  	// test get by index
   111  	if val := valSet.GetByIndex(uint64(0)); !reflect.DeepEqual(val, val1) {
   112  		t.Errorf("validator mismatch:")
   113  		t.Errorf("  Address(): %v, %v", val.Address(), val1.Address())
   114  		t.Errorf("  String(): %v, %v", val.String(), val1.String())
   115  		t.Errorf("  RewardAddresS(): %v, %v", val.RewardAddress(), val1.RewardAddress())
   116  		t.Errorf("  VotingPower(): %v, %v", val.VotingPower(), val1.VotingPower())
   117  		t.Errorf("  Weight(): %v, %v", val.Weight(), val1.Weight())
   118  	}
   119  
   120  	// test get by invalid index
   121  	if val := valSet.GetByIndex(uint64(2)); val != nil {
   122  		t.Errorf("validator mismatch: have %v, want nil", val)
   123  	}
   124  
   125  	// test get by address
   126  	if _, val := valSet.GetByAddress(addr2); !reflect.DeepEqual(val, val2) {
   127  		t.Errorf("validator mismatch: have %v, want %v", val, val2)
   128  	}
   129  
   130  	// test get by invalid address
   131  	invalidAddr := common.HexToAddress("0x9535b2e7faaba5288511d89341d94a38063a349b")
   132  	if _, val := valSet.GetByAddress(invalidAddr); val != nil {
   133  		t.Errorf("validator mismatch: have %v, want nil", val)
   134  	}
   135  
   136  	// test get proposer
   137  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   138  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   139  	}
   140  
   141  	// test calculate proposer
   142  	lastProposer := addr1
   143  	valSet.CalcProposer(lastProposer, uint64(0))
   144  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   145  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   146  	}
   147  
   148  	valSet.CalcProposer(lastProposer, uint64(1))
   149  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   150  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   151  	}
   152  
   153  	valSet.CalcProposer(lastProposer, uint64(2))
   154  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   155  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   156  	}
   157  
   158  	valSet.CalcProposer(lastProposer, uint64(5))
   159  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   160  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   161  	}
   162  
   163  	// test empty last proposer
   164  	lastProposer = common.Address{}
   165  	valSet.CalcProposer(lastProposer, uint64(3))
   166  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   167  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   168  	}
   169  }
   170  
   171  func TestEmptyWeightedCouncil(t *testing.T) {
   172  	valSet := NewWeightedCouncil(ExtractValidators([]byte{}), nil, nil, nil, nil, istanbul.WeightedRandom, 0, 0, 0, &blockchain.BlockChain{})
   173  	if valSet == nil {
   174  		t.Errorf("validator set should not be nil")
   175  	}
   176  }
   177  
   178  func TestNewWeightedCouncil_InvalidPolicy(t *testing.T) {
   179  	// Invalid proposer policy
   180  	valSet := NewWeightedCouncil(ExtractValidators([]byte{}), nil, nil, nil, nil, istanbul.Sticky, 0, 0, 0, &blockchain.BlockChain{})
   181  	assert.Equal(t, (*weightedCouncil)(nil), valSet)
   182  
   183  	valSet = NewWeightedCouncil(ExtractValidators([]byte{}), nil, nil, nil, nil, istanbul.RoundRobin, 0, 0, 0, &blockchain.BlockChain{})
   184  	assert.Equal(t, (*weightedCouncil)(nil), valSet)
   185  }
   186  
   187  func TestNewWeightedCouncil_IncompleteParams(t *testing.T) {
   188  	const ValCnt = 3
   189  	var validators []istanbul.Validator
   190  	var rewardAddrs []common.Address
   191  	var votingPowers []uint64
   192  	var weights []uint64
   193  
   194  	// Create 3 validators with random addresses
   195  	b := []byte{}
   196  	for i := 0; i < ValCnt; i++ {
   197  		key, _ := crypto.GenerateKey()
   198  		addr := crypto.PubkeyToAddress(key.PublicKey)
   199  		val := New(addr)
   200  		validators = append(validators, val)
   201  		b = append(b, val.Address().Bytes()...)
   202  
   203  		rewardKey, _ := crypto.GenerateKey()
   204  		rewardAddr := crypto.PubkeyToAddress(rewardKey.PublicKey)
   205  		rewardAddrs = append(rewardAddrs, rewardAddr)
   206  
   207  		votingPowers = append(votingPowers, uint64(1))
   208  		weights = append(weights, uint64(1))
   209  	}
   210  
   211  	// No validator address
   212  	valSet := NewWeightedCouncil(ExtractValidators([]byte{}), nil, rewardAddrs, votingPowers, weights, istanbul.WeightedRandom, 0, 0, 0, &blockchain.BlockChain{})
   213  	assert.Equal(t, (*weightedCouncil)(nil), valSet)
   214  
   215  	// Incomplete rewardAddrs
   216  	incompleteRewardAddrs := make([]common.Address, 1)
   217  	valSet = NewWeightedCouncil(ExtractValidators(b), nil, incompleteRewardAddrs, nil, nil, istanbul.WeightedRandom, 0, 0, 0, &blockchain.BlockChain{})
   218  	assert.Equal(t, (*weightedCouncil)(nil), valSet)
   219  
   220  	// Incomplete rewardAddrs
   221  	incompleteVotingPowers := make([]uint64, 1)
   222  	valSet = NewWeightedCouncil(ExtractValidators(b), nil, nil, incompleteVotingPowers, nil, istanbul.WeightedRandom, 0, 0, 0, &blockchain.BlockChain{})
   223  	assert.Equal(t, (*weightedCouncil)(nil), valSet)
   224  
   225  	// Incomplete rewardAddrs
   226  	incompleteWeights := make([]uint64, 1)
   227  	valSet = NewWeightedCouncil(ExtractValidators(b), nil, nil, nil, incompleteWeights, istanbul.WeightedRandom, 0, 0, 0, &blockchain.BlockChain{})
   228  	assert.Equal(t, (*weightedCouncil)(nil), valSet)
   229  }