github.com/klaytn/klaytn@v1.10.2/consensus/istanbul/validator/weighted_random_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  	"math/rand"
    22  	"reflect"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/klaytn/klaytn/common"
    30  	"github.com/klaytn/klaytn/consensus/istanbul"
    31  	"github.com/klaytn/klaytn/crypto"
    32  	"github.com/klaytn/klaytn/fork"
    33  	"github.com/klaytn/klaytn/params"
    34  	"github.com/stretchr/testify/assert"
    35  )
    36  
    37  var (
    38  	testAddrs = []common.Address{
    39  		common.HexToAddress("0x0adBC7b05Da383157200a9Fa192285898aB2CaAc"),
    40  		common.HexToAddress("0x371F315BeBe961776AC84B29e044b01074b93E69"),
    41  		common.HexToAddress("0x5845EAa7ac251542Dc96fBaD09E3CAd3ec105a7a"),
    42  		common.HexToAddress("0x63805D23fC86Aa16EFB157C036F226f3aa93099d"),
    43  		common.HexToAddress("0x68E0DEf1e6beb308eF5FdF2e19dB2884571c465c"),
    44  		common.HexToAddress("0x72E23aAe2Cc6eE54682bD67B6093F7b7971f3D2F"),
    45  		common.HexToAddress("0x78B898e37A45069518775972AB8155493e69A2F0"),
    46  		common.HexToAddress("0x8704Ffb473a16638ea42c7704995d6505102a4Ca"),
    47  		common.HexToAddress("0x93d3Ce8940c7907b0C1c3898dF7Aa797C457cD0f"),
    48  		common.HexToAddress("0x9a049EefC01aAE911F2B6F19d724dF9d3ca5cAe6"),
    49  		common.HexToAddress("0xC14124d61fc940c7aF29F62438D1B54fD7FFB65B"),
    50  		common.HexToAddress("0xc4cB0B3c2682C15D96739f9a13fE26f17c893f8f"),
    51  		common.HexToAddress("0xd4aB68fcEC8Fa23856188163B131F3E443e09EF8"),
    52  	}
    53  	testRewardAddrs = []common.Address{
    54  		common.HexToAddress("0x0a6e50a28f10CD9dba36DD9D3B95BaA32F9fe77a"),
    55  		common.HexToAddress("0x23FB6C77E069BD6456181f48a9c77f3a3812E7e7"),
    56  		common.HexToAddress("0x43d5e084D8A6c7FbCd0EbA9a517533fF384f0577"),
    57  		common.HexToAddress("0x4d180C12FB3B061f44E91D30d574F78D1DeCAD90"),
    58  		common.HexToAddress("0x53094cE69ea701bfb9D06239087d4CF09F127B78"),
    59  		common.HexToAddress("0x5F2152bf0C97f1d2c3Ffec8A98FEEB1e50798090"),
    60  		common.HexToAddress("0x653f42fb1F3474de222F7DDa2109250218989B19"),
    61  		common.HexToAddress("0x93eaEAa38D534B52E7DB3AB939330022330cD427"),
    62  		common.HexToAddress("0x96a0d7f6A82B860313FF8668b858aD4930d7B2d6"),
    63  		common.HexToAddress("0xB89ff800C21b3334f0e355A73242bB4363cf6e10"),
    64  		common.HexToAddress("0xDEeeF6fAC16f095Fa944E481F8e6c3b42ae3Cefa"),
    65  		common.HexToAddress("0xbDE3Ee8c01484dDBD59a425457Ab138cf3aa0E11"),
    66  		common.HexToAddress("0xdD5572A7aC7AB7407e8e4082dB442668C02924E3"),
    67  	}
    68  	testStakingAddrs = []common.Address{
    69  		common.HexToAddress("0x3776A66698babFA24F0316e4363B2E6C95B09ceF"),
    70  		common.HexToAddress("0x4d086A88329233E00158FEcbe7b38Dd8667Dd9f9"),
    71  		common.HexToAddress("0x5d7d13278AEF56263B7d25d51E1B2519Ac0D656B"),
    72  		common.HexToAddress("0x60fA2326f6C1A7a90Bd1B3c31Bd1A7f9Aed61443"),
    73  		common.HexToAddress("0x681C55B2CD831D262C785e213a70e277D0226c79"),
    74  		common.HexToAddress("0x6EeA09FF2bB16F1cD075c748E1684f1100085541"),
    75  		common.HexToAddress("0x817617C3f09d08a5d475bf72b4723A755CD9b8c7"),
    76  		common.HexToAddress("0x83F28D3512dC32701F375b112d0CB0810Cb736e4"),
    77  		common.HexToAddress("0x92D03E4998fB3F91A1E24496EDCf625136037f9e"),
    78  		common.HexToAddress("0xA0360cDC935A9f3bFe7Ad03D1C34989427ad239f"),
    79  		common.HexToAddress("0xE2946677DcEEDDF36F1f6EA00421635804872D49"),
    80  		common.HexToAddress("0xF246283a57A8018085AF39bdadFCC4aaC682e6dD"),
    81  		common.HexToAddress("0xF3c6f39e231C7363F9B5F4d71b5EE7Eb1fB265d7"),
    82  	}
    83  	testVotingPowers = []uint64{
    84  		1, 1, 1, 1, 1,
    85  		1, 1, 1, 1, 1,
    86  		1, 1, 1,
    87  	}
    88  	testZeroWeights = []uint64{
    89  		0, 0, 0, 0, 0,
    90  		0, 0, 0, 0, 0,
    91  		0, 0, 0,
    92  	}
    93  	testPrevHash = common.HexToHash("0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a")
    94  
    95  	testExpectedProposers = []common.Address{
    96  		common.HexToAddress("0x8704Ffb473a16638ea42c7704995d6505102a4Ca"),
    97  		common.HexToAddress("0xC14124d61fc940c7aF29F62438D1B54fD7FFB65B"),
    98  		common.HexToAddress("0x72E23aAe2Cc6eE54682bD67B6093F7b7971f3D2F"),
    99  		common.HexToAddress("0xc4cB0B3c2682C15D96739f9a13fE26f17c893f8f"),
   100  		common.HexToAddress("0x68E0DEf1e6beb308eF5FdF2e19dB2884571c465c"),
   101  		common.HexToAddress("0x371F315BeBe961776AC84B29e044b01074b93E69"),
   102  		common.HexToAddress("0x63805D23fC86Aa16EFB157C036F226f3aa93099d"),
   103  		common.HexToAddress("0x93d3Ce8940c7907b0C1c3898dF7Aa797C457cD0f"),
   104  		common.HexToAddress("0x5845EAa7ac251542Dc96fBaD09E3CAd3ec105a7a"),
   105  		common.HexToAddress("0x78B898e37A45069518775972AB8155493e69A2F0"),
   106  		common.HexToAddress("0x0adBC7b05Da383157200a9Fa192285898aB2CaAc"),
   107  		common.HexToAddress("0xd4aB68fcEC8Fa23856188163B131F3E443e09EF8"),
   108  		common.HexToAddress("0x9a049EefC01aAE911F2B6F19d724dF9d3ca5cAe6"),
   109  	}
   110  
   111  	testNonZeroWeights = []uint64{
   112  		1, 1, 2, 1, 1,
   113  		1, 0, 3, 2, 1,
   114  		0, 1, 5,
   115  	}
   116  )
   117  
   118  func makeTestValidators(weights []uint64) (validators istanbul.Validators) {
   119  	validators = make([]istanbul.Validator, len(testAddrs))
   120  	for i := range testAddrs {
   121  		validators[i] = newWeightedValidator(testAddrs[i], testRewardAddrs[i], testVotingPowers[i], weights[i])
   122  	}
   123  	sort.Sort(validators)
   124  
   125  	return
   126  }
   127  
   128  func makeTestWeightedCouncil(weights []uint64) (valSet *weightedCouncil) {
   129  	// prepare weighted council
   130  	valSet = NewWeightedCouncil(testAddrs, nil, testRewardAddrs, testVotingPowers, weights, istanbul.WeightedRandom, 21, 0, 0, nil)
   131  	return
   132  }
   133  
   134  func TestWeightedCouncil_List(t *testing.T) {
   135  	validators := makeTestValidators(testZeroWeights)
   136  
   137  	valSet := makeTestWeightedCouncil(testZeroWeights)
   138  
   139  	validators_in_valset := valSet.List()
   140  
   141  	if len(validators_in_valset) != len(validators) {
   142  		t.Errorf("len of validators in valSet is different from len of given test set %v, validators %v", len(validators_in_valset), len(validators))
   143  	}
   144  
   145  	for i := 0; i < len(validators); i++ {
   146  		if validators[i].String() != validators_in_valset[i].String() {
   147  			t.Errorf("The element in validators in valset is different from given test set%v, validators %v", validators_in_valset[i], validators[i])
   148  		}
   149  	}
   150  }
   151  
   152  func TestWeightedCouncil_GetByIndex(t *testing.T) {
   153  	validators := makeTestValidators(testZeroWeights)
   154  	valSet := makeTestWeightedCouncil(testZeroWeights)
   155  
   156  	for i := 0; i < len(validators); i++ {
   157  		validatorToCheck := valSet.GetByIndex(uint64(i))
   158  
   159  		if validators[i].Address() != validatorToCheck.Address() {
   160  			t.Errorf("The validator with given index is different. index=%v, expected validator=%v, gotten validator %v", i, validators[i], valSet.GetByIndex(uint64(i)))
   161  		}
   162  	}
   163  
   164  	for errorIndex := len(validators) + 1; errorIndex < 100; errorIndex++ {
   165  		validatorToCheck := valSet.GetByIndex(uint64(errorIndex))
   166  
   167  		if validatorToCheck != nil {
   168  			t.Errorf("The result should be nil with given index. index=%v", errorIndex)
   169  		}
   170  	}
   171  
   172  	for errorIndex := -1; errorIndex > -100; errorIndex-- {
   173  		validatorToCheck := valSet.GetByIndex(uint64(errorIndex))
   174  
   175  		if validatorToCheck != nil {
   176  			t.Errorf("The result should be nil with given index. index=%v", errorIndex)
   177  		}
   178  	}
   179  }
   180  
   181  func TestWeightedCouncil_GetByAddress(t *testing.T) {
   182  	validators := makeTestValidators(testZeroWeights)
   183  	valSet := makeTestWeightedCouncil(testZeroWeights)
   184  
   185  	for i := 0; i < len(validators); i++ {
   186  		index, validatorToCheck := valSet.getByAddress(validators[i].Address())
   187  
   188  		if validators[index].Address() != validatorToCheck.Address() {
   189  			t.Errorf("The validator with given address is different index=%v, expected validator=%v, gotten validator %v", i, validators[i], valSet.GetByIndex(uint64(i)))
   190  		}
   191  	}
   192  
   193  	_, errorValidator := valSet.getByAddress(common.Address{})
   194  	if errorValidator != nil {
   195  		t.Errorf("The validator with given address should be nil.")
   196  	}
   197  }
   198  
   199  func TestWeightedCouncil_GetProposer(t *testing.T) {
   200  	validators := makeTestValidators(testZeroWeights)
   201  	valSet := makeTestWeightedCouncil(testZeroWeights)
   202  
   203  	// at the first, proposer is the first validator in the validator list
   204  	expectedProposer := validators[0]
   205  	proposerToCheck := valSet.GetProposer()
   206  
   207  	if expectedProposer.Address() != proposerToCheck.Address() {
   208  		t.Errorf("proposer should be same. Expected proposer: %v, gotten proposer %v", expectedProposer, proposerToCheck)
   209  	}
   210  
   211  	// random check. give random validator to valSet and check GetProposer() if it is same as the given validator
   212  	r := rand.New(rand.NewSource(time.Now().Unix()))
   213  	for i := 0; i < 100; i++ {
   214  		choosenIndex := r.Intn(len(validators))
   215  
   216  		valSet.proposer.Store(validators[choosenIndex])
   217  
   218  		expectedProposer := validators[choosenIndex]
   219  		proposerToCheck := valSet.GetProposer()
   220  
   221  		if expectedProposer.Address() != proposerToCheck.Address() {
   222  			t.Errorf("proposer should be same. Expected proposer: %v, gotten proposer %v", expectedProposer, proposerToCheck)
   223  		}
   224  	}
   225  }
   226  
   227  func TestDefaultSet_IsProposer(t *testing.T) {
   228  	validators := makeTestValidators(testZeroWeights)
   229  	valSet := makeTestWeightedCouncil(testZeroWeights)
   230  
   231  	currentProposer := valSet.GetProposer()
   232  
   233  	for i := 0; i < len(validators); i++ {
   234  		validatorToTest := validators[i]
   235  
   236  		expectedResult := validatorToTest.Address() == currentProposer.Address()
   237  		result := valSet.IsProposer(validatorToTest.Address())
   238  
   239  		if result != expectedResult {
   240  			t.Errorf("The result is different from the expected result. Expected Result : %v, Gotten Result : %v, CurrentProposer Address : %v, TestValidator Address : %v", expectedResult, result, currentProposer.Address(), validatorToTest.Address())
   241  		}
   242  	}
   243  }
   244  
   245  func TestWeightedCouncil_RefreshWithZeroWeight(t *testing.T) {
   246  	validators := makeTestValidators(testZeroWeights)
   247  
   248  	valSet := makeTestWeightedCouncil(testZeroWeights)
   249  	runRefreshForTest(valSet)
   250  
   251  	// Run tests
   252  
   253  	// 1. check all validators are chosen for proposers
   254  	var sortedProposers istanbul.Validators
   255  	sortedProposers = make([]istanbul.Validator, len(testAddrs))
   256  	copy(sortedProposers, valSet.proposers)
   257  	sort.Sort(sortedProposers)
   258  	if !reflect.DeepEqual(sortedProposers, validators) {
   259  		t.Errorf("All validators are not in proposers: sorted proposers %v, validators %v", sortedProposers, validators)
   260  	}
   261  
   262  	// 2. check proposers
   263  	for i, val := range valSet.proposers {
   264  		if !reflect.DeepEqual(val.Address(), testExpectedProposers[i]) {
   265  			t.Errorf("proposer mismatch: have %v, want %v", val.Address().String(), testExpectedProposers[i].String())
   266  		}
   267  	}
   268  
   269  	// 3. test calculate proposer different round
   270  	checkCalcProposerWithRound(t, valSet, testAddrs[0], 0)
   271  	checkCalcProposerWithRound(t, valSet, testAddrs[0], 1)
   272  	checkCalcProposerWithRound(t, valSet, testAddrs[0], 5)
   273  	checkCalcProposerWithRound(t, valSet, testAddrs[0], 13)
   274  	checkCalcProposerWithRound(t, valSet, testAddrs[0], 1000)
   275  
   276  	// 4. test calculate proposer different block number
   277  	for i := 0; i < 100; i++ {
   278  		valSet.blockNum = uint64(i)
   279  		checkCalcProposerWithBlockNumber(t, valSet, testAddrs[0], 0)
   280  	}
   281  
   282  	// 5. test calculate proposer different block number and round
   283  	for i := 0; i < 100; i++ {
   284  		valSet.blockNum = uint64(i)
   285  		for j := 0; j < 100; j++ {
   286  			round := uint64(j)
   287  			checkCalcProposerWithBlockNumberAndRound(t, valSet, testAddrs[0], round)
   288  		}
   289  	}
   290  }
   291  
   292  func checkCalcProposerWithRound(t *testing.T, valSet *weightedCouncil, lastProposer common.Address, round uint64) {
   293  	valSet.CalcProposer(lastProposer, round)
   294  	_, expectedVal := valSet.GetByAddress(testExpectedProposers[round%uint64(len(valSet.proposers))])
   295  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, expectedVal) {
   296  		t.Errorf("proposer mismatch: have %v, want %v", val.String(), expectedVal.Address().String())
   297  	}
   298  }
   299  
   300  func checkCalcProposerWithBlockNumber(t *testing.T, valSet *weightedCouncil, lastProposer common.Address, round uint64) {
   301  	valSet.CalcProposer(lastProposer, round)
   302  	_, expectedVal := valSet.GetByAddress(testExpectedProposers[valSet.blockNum%uint64(len(valSet.proposers))])
   303  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, expectedVal) {
   304  		t.Errorf("proposer mismatch: have %v, want %v", val.String(), expectedVal.Address().String())
   305  	}
   306  }
   307  
   308  func checkCalcProposerWithBlockNumberAndRound(t *testing.T, valSet *weightedCouncil, lastProposer common.Address, round uint64) {
   309  	valSet.CalcProposer(lastProposer, round)
   310  	_, expectedVal := valSet.GetByAddress(testExpectedProposers[(valSet.blockNum+round)%uint64(len(valSet.proposers))])
   311  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, expectedVal) {
   312  		t.Errorf("proposer mismatch: have %v, want %v", val.String(), expectedVal.Address().String())
   313  	}
   314  }
   315  
   316  func TestWeightedCouncil_RefreshWithNonZeroWeight(t *testing.T) {
   317  	validators := makeTestValidators(testNonZeroWeights)
   318  
   319  	valSet := makeTestWeightedCouncil(testNonZeroWeights)
   320  	runRefreshForTest(valSet)
   321  
   322  	// Run tests
   323  
   324  	// 1. number of proposers
   325  	totalWeights := uint64(0)
   326  	for _, v := range validators {
   327  		totalWeights += v.Weight()
   328  	}
   329  	assert.Equal(t, totalWeights, uint64(len(valSet.proposers)))
   330  
   331  	// 2. weight and appearance frequency
   332  	for _, v := range validators {
   333  		weight := v.Weight()
   334  		appearance := uint64(0)
   335  		for _, p := range valSet.proposers {
   336  			if v.Address() == p.Address() {
   337  				appearance++
   338  			}
   339  		}
   340  		assert.Equal(t, weight, appearance)
   341  	}
   342  }
   343  
   344  func TestWeightedCouncil_RemoveValidator(t *testing.T) {
   345  	validators := makeTestValidators(testNonZeroWeights)
   346  	valSet := makeTestWeightedCouncil(testNonZeroWeights)
   347  	runRefreshForTest(valSet)
   348  
   349  	for _, val := range validators {
   350  
   351  		_, removedVal := valSet.GetByAddress(val.Address())
   352  		if removedVal == nil {
   353  			t.Errorf("Fail to find validator with address %v", removedVal.Address().String())
   354  		}
   355  
   356  		if !valSet.RemoveValidator(removedVal.Address()) {
   357  			t.Errorf("Fail to remove validator %v", removedVal.String())
   358  		}
   359  
   360  		// check whether removedVal is really removed from validators
   361  		for _, v := range valSet.validators {
   362  			if removedVal.Address() == v.Address() {
   363  				t.Errorf("Validator(%v) does not removed from validators", removedVal.Address().String())
   364  			}
   365  		}
   366  
   367  		// check whether removedVal is also removed from proposers immediately
   368  		for _, p := range valSet.proposers {
   369  			if removedVal.Address() == p.Address() {
   370  				t.Errorf("Validator(%v) does not removed from proposers", removedVal.Address().String())
   371  			}
   372  		}
   373  	}
   374  
   375  	assert.Equal(t, uint64(0), valSet.Size())
   376  	assert.Equal(t, 0, len(valSet.Proposers()))
   377  }
   378  
   379  func TestWeightedCouncil_RefreshAfterRemoveValidator(t *testing.T) {
   380  	validators := makeTestValidators(testNonZeroWeights)
   381  	valSet := makeTestWeightedCouncil(testNonZeroWeights)
   382  	runRefreshForTest(valSet)
   383  
   384  	for _, val := range validators {
   385  
   386  		_, removedVal := valSet.GetByAddress(val.Address())
   387  		if removedVal == nil {
   388  			t.Errorf("Fail to find validator with address %v", removedVal.Address().String())
   389  		}
   390  
   391  		if !valSet.RemoveValidator(removedVal.Address()) {
   392  			t.Errorf("Fail to remove validator %v", removedVal.String())
   393  		}
   394  
   395  		// check whether removedVal is really removed from validators
   396  		for _, v := range valSet.validators {
   397  			if removedVal.Address() == v.Address() {
   398  				t.Errorf("Validator(%v) does not removed from validators", removedVal.Address().String())
   399  			}
   400  		}
   401  
   402  		runRefreshForTest(valSet)
   403  
   404  		// check whether removedVal is excluded as expected when refreshing proposers
   405  		for _, p := range valSet.proposers {
   406  			if removedVal.Address() == p.Address() {
   407  				t.Errorf("Validator(%v) does not removed from proposers", removedVal.Address().String())
   408  			}
   409  		}
   410  	}
   411  
   412  	assert.Equal(t, uint64(0), valSet.Size())
   413  	assert.Equal(t, 0, len(valSet.Proposers()))
   414  }
   415  
   416  func runRefreshForTest(valSet *weightedCouncil) {
   417  	hashString := strings.TrimPrefix(testPrevHash.Hex(), "0x")
   418  	if len(hashString) > 15 {
   419  		hashString = hashString[:15]
   420  	}
   421  	seed, _ := strconv.ParseInt(hashString, 16, 64)
   422  	valSet.refreshProposers(seed, 0)
   423  }
   424  
   425  func TestWeightedCouncil_SetSubGroupSize(t *testing.T) {
   426  	validators := makeTestValidators(testNonZeroWeights)
   427  	valSet := makeTestWeightedCouncil(testNonZeroWeights)
   428  
   429  	validatorsLen := len(validators)
   430  
   431  	for i := 1; i < validatorsLen; i++ {
   432  		valSet.SetSubGroupSize(uint64(i))
   433  
   434  		expectedSubGroupSize := uint64(i)
   435  		gottenSubGroupSize := valSet.SubGroupSize()
   436  
   437  		if expectedSubGroupSize != gottenSubGroupSize {
   438  			t.Errorf("SubGroupSize should be %v but gotten SubGroupSize is %v", expectedSubGroupSize, gottenSubGroupSize)
   439  		}
   440  	}
   441  }
   442  
   443  func TestWeightedCouncil_SubListWithProposer(t *testing.T) {
   444  	var (
   445  		validators = makeTestValidators(testNonZeroWeights)
   446  		prevHash   = crypto.Keccak256Hash([]byte("This is a test"))
   447  		valSet     = makeTestWeightedCouncil(testNonZeroWeights)
   448  
   449  		BlockBeforeHF = big.NewInt(4)
   450  		HFBlock       = big.NewInt(5)
   451  		BlockAfterHF  = big.NewInt(6)
   452  
   453  		expectIndexOfSubsetLenTest                     = []int{1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10}
   454  		expectIndexOfRoundTestBeforeIstanbulCompatible = [][]int{
   455  			{1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10},
   456  			{2, 3, 7, 1, 11, 6, 9, 4, 0, 8, 12, 10},
   457  			{3, 4, 7, 1, 11, 6, 9, 2, 0, 8, 12, 10},
   458  			{4, 5, 7, 1, 11, 6, 9, 2, 0, 8, 12, 10},
   459  			{5, 6, 7, 1, 11, 4, 9, 2, 0, 8, 12, 10},
   460  			{6, 7, 5, 1, 11, 4, 9, 2, 0, 8, 12, 10},
   461  			{7, 8, 5, 1, 11, 4, 9, 2, 0, 6, 12, 10},
   462  			{8, 9, 5, 1, 11, 4, 7, 2, 0, 6, 12, 10},
   463  			{9, 10, 5, 1, 11, 4, 7, 2, 0, 6, 12, 8},
   464  			{10, 11, 5, 1, 9, 4, 7, 2, 0, 6, 12, 8},
   465  			{11, 12, 5, 1, 9, 4, 7, 2, 0, 6, 10, 8},
   466  			{12, 0, 6, 2, 10, 5, 8, 3, 1, 7, 11, 9},
   467  			{0, 1, 7, 3, 11, 6, 9, 4, 2, 8, 12, 10},
   468  			{1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10},
   469  			{2, 3, 7, 1, 11, 6, 9, 4, 0, 8, 12, 10},
   470  		}
   471  		expectIndexOfRoundTestAfterIstanbulCompatible = [][]int{
   472  			{1, 2, 7, 3, 11, 6, 9, 4, 0, 8, 12, 10},
   473  			{2, 3, 6, 8, 10, 9, 1, 11, 5, 0, 4, 7},
   474  			{3, 4, 10, 5, 8, 0, 7, 9, 12, 6, 1, 11},
   475  			{4, 5, 6, 0, 7, 1, 3, 12, 2, 8, 9, 11},
   476  			{5, 6, 4, 9, 12, 7, 0, 3, 8, 2, 1, 11},
   477  			{6, 7, 2, 3, 8, 9, 11, 12, 5, 1, 4, 0},
   478  			{7, 8, 3, 11, 5, 10, 0, 1, 2, 6, 9, 12},
   479  			{8, 9, 5, 7, 11, 3, 1, 0, 10, 6, 4, 12},
   480  			{9, 10, 3, 7, 5, 6, 2, 0, 12, 8, 11, 1},
   481  			{10, 11, 7, 1, 0, 9, 8, 6, 12, 5, 2, 4},
   482  			{11, 12, 4, 8, 1, 6, 0, 3, 9, 10, 2, 7},
   483  			{12, 0, 7, 2, 4, 1, 6, 10, 9, 11, 8, 3},
   484  			{0, 1, 9, 8, 2, 3, 10, 5, 7, 12, 4, 6},
   485  			{1, 2, 11, 10, 6, 8, 7, 4, 9, 12, 0, 5},
   486  			{2, 3, 4, 8, 6, 5, 11, 1, 12, 0, 9, 10},
   487  		}
   488  	)
   489  
   490  	getExpectSubList := func(indices []int) []istanbul.Validator {
   491  		var expectSubList []istanbul.Validator
   492  		for _, index := range indices {
   493  			expectSubList = append(expectSubList, validators[index])
   494  		}
   495  		return expectSubList
   496  	}
   497  
   498  	fork.SetHardForkBlockNumberConfig(&params.ChainConfig{IstanbulCompatibleBlock: HFBlock})
   499  	defer fork.ClearHardForkBlockNumberConfig()
   500  
   501  	// SubsetLen test: various subset length test
   502  	valSet.SetBlockNum(1)
   503  	for testSubsetLen := 2; testSubsetLen < len(validators); testSubsetLen++ {
   504  		// set committee size and calculate proposer
   505  		valSet.SetSubGroupSize(uint64(testSubsetLen))
   506  		valSet.CalcProposer(valSet.GetProposer().Address(), uint64(0))
   507  
   508  		// get committee list
   509  		expectSubList := getExpectSubList(expectIndexOfSubsetLenTest[0:testSubsetLen])
   510  
   511  		// compare the subList of valSet with expected committee list
   512  		viewBeforeHF := &istanbul.View{Sequence: BlockBeforeHF, Round: big.NewInt(int64(0))}
   513  		viewAfterHF := &istanbul.View{Sequence: BlockAfterHF, Round: big.NewInt(int64(0))}
   514  		assert.Equal(t, expectSubList, valSet.SubList(prevHash, viewBeforeHF), "test Subset length: %d(before istanbulCompatible)", testSubsetLen)
   515  		assert.Equal(t, expectSubList, valSet.SubList(prevHash, viewAfterHF), "test subset length: %d(after istanbulCompatible)", testSubsetLen)
   516  	}
   517  
   518  	// Check: compare the size of the test data arrays
   519  	assert.Equal(t, len(expectIndexOfRoundTestBeforeIstanbulCompatible), len(expectIndexOfRoundTestAfterIstanbulCompatible))
   520  
   521  	// Round test: various round test
   522  	valSet.SetBlockNum(1)
   523  	valSet.SetSubGroupSize(uint64(len(validators) - 1))
   524  	for round := 0; round < len(expectIndexOfRoundTestBeforeIstanbulCompatible); round++ {
   525  		// calculate proposer and set view with test round value
   526  		valSet.CalcProposer(valSet.GetProposer().Address(), uint64(round))
   527  
   528  		// get committee list
   529  		expectSubListBeforeHF := getExpectSubList(expectIndexOfRoundTestBeforeIstanbulCompatible[round])
   530  		expectSubListAfterHF := getExpectSubList(expectIndexOfRoundTestAfterIstanbulCompatible[round])
   531  
   532  		// compare the subList of valSet with expected committee list
   533  		viewBeforeHF := &istanbul.View{Sequence: BlockBeforeHF, Round: big.NewInt(int64(round))}
   534  		viewAfterHF := &istanbul.View{Sequence: BlockAfterHF, Round: big.NewInt(int64(round))}
   535  		assert.Equal(t, expectSubListBeforeHF, valSet.SubList(prevHash, viewBeforeHF), "test round: %d(before istanbulCompatible)", round)
   536  		assert.Equal(t, expectSubListAfterHF, valSet.SubList(prevHash, viewAfterHF), "test round: %d(after istanbulCompatible)", round)
   537  	}
   538  }
   539  
   540  func TestWeightedCouncil_Copy(t *testing.T) {
   541  	valSet := makeTestWeightedCouncil(testNonZeroWeights)
   542  
   543  	copiedValSet := valSet.Copy().(*weightedCouncil)
   544  
   545  	// check each variable is same except selector(function)
   546  	if valSet.blockNum != copiedValSet.blockNum || valSet.GetProposer() != copiedValSet.GetProposer() ||
   547  		valSet.subSize != copiedValSet.subSize || valSet.policy != copiedValSet.policy ||
   548  		valSet.proposersBlockNum != copiedValSet.proposersBlockNum ||
   549  		!reflect.DeepEqual(valSet.validators, copiedValSet.validators) ||
   550  		!reflect.DeepEqual(valSet.proposers, copiedValSet.proposers) ||
   551  		!reflect.DeepEqual(valSet.stakingInfo, copiedValSet.stakingInfo) {
   552  		t.Errorf("copied weightedCouncil is different from original.")
   553  		t.Errorf("block number. original : %v, Copied : %v", valSet.blockNum, copiedValSet.blockNum)
   554  		t.Errorf("proposer. original : %v, Copied : %v", valSet.GetProposer(), copiedValSet.GetProposer())
   555  		t.Errorf("subSize. original : %v, Copied : %v", valSet.subSize, copiedValSet.subSize)
   556  		t.Errorf("policy. original : %v, Copied : %v", valSet.policy, copiedValSet.policy)
   557  		t.Errorf("proposersBlockNum. original : %v, Copied : %v", valSet.proposersBlockNum, copiedValSet.proposersBlockNum)
   558  		t.Errorf("validators. original : %v, Copied : %v", valSet.validators, copiedValSet.validators)
   559  		t.Errorf("proposers. original : %v, Copied : %v", valSet.proposers, copiedValSet.proposers)
   560  		t.Errorf("staking. original : %v, Copied : %v", valSet.stakingInfo, copiedValSet.stakingInfo)
   561  	}
   562  }