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

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2017 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from quorum/consensus/istanbul/validator/default_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package validator
    22  
    23  import (
    24  	"fmt"
    25  	"math/big"
    26  	"reflect"
    27  	"strings"
    28  	"testing"
    29  
    30  	"github.com/klaytn/klaytn/common"
    31  	"github.com/klaytn/klaytn/consensus/istanbul"
    32  	"github.com/klaytn/klaytn/crypto"
    33  	"github.com/klaytn/klaytn/fork"
    34  	"github.com/klaytn/klaytn/params"
    35  	"github.com/stretchr/testify/assert"
    36  )
    37  
    38  var (
    39  	testAddress  = "136807B12327a8AfF9831F09617dA1B9D398cda2"
    40  	testAddress2 = "4dd324F9821485caE941640B32c3Bcf1fA6E93E6"
    41  	testAddress3 = "62E47d858bf8513fc401886B94E33e7DCec2Bfb7"
    42  	testAddress4 = "8aD8F547fa00f58A8c4fb3B671Ee5f1A75bA028a"
    43  	testAddress5 = "dd197E88fd97aF3877023cf20d69543fc72e6298"
    44  )
    45  
    46  func TestNewValidatorSet(t *testing.T) {
    47  	var validators []istanbul.Validator
    48  	const ValCnt = 100
    49  
    50  	// Create 100 validators with random addresses
    51  	b := []byte{}
    52  	for i := 0; i < ValCnt; i++ {
    53  		key, _ := crypto.GenerateKey()
    54  		addr := crypto.PubkeyToAddress(key.PublicKey)
    55  		val := New(addr)
    56  		validators = append(validators, val)
    57  		b = append(b, val.Address().Bytes()...)
    58  	}
    59  
    60  	// Create ValidatorSet
    61  	valSet := NewSet(ExtractValidators(b), istanbul.RoundRobin)
    62  	if valSet == nil {
    63  		t.Errorf("the validator byte array cannot be parsed")
    64  		t.FailNow()
    65  	}
    66  
    67  	// Check validators sorting: should be in ascending order
    68  	for i := 0; i < ValCnt-1; i++ {
    69  		val := valSet.GetByIndex(uint64(i))
    70  		nextVal := valSet.GetByIndex(uint64(i + 1))
    71  		if strings.Compare(val.String(), nextVal.String()) >= 0 {
    72  			t.Errorf("validator set is not sorted in descending order")
    73  		}
    74  	}
    75  }
    76  
    77  func TestNormalValSet(t *testing.T) {
    78  	b1 := common.Hex2Bytes(testAddress)
    79  	b2 := common.Hex2Bytes(testAddress2)
    80  	addr1 := common.BytesToAddress(b1)
    81  	addr2 := common.BytesToAddress(b2)
    82  	val1 := New(addr1)
    83  	val2 := New(addr2)
    84  
    85  	valSet := newDefaultSet([]common.Address{addr1, addr2}, istanbul.RoundRobin)
    86  	if valSet == nil {
    87  		t.Errorf("the format of validator set is invalid")
    88  		t.FailNow()
    89  	}
    90  
    91  	// check size
    92  	if size := valSet.Size(); size != 2 {
    93  		t.Errorf("the size of validator set is wrong: have %v, want 2", size)
    94  	}
    95  	// test get by index
    96  	if val := valSet.GetByIndex(uint64(0)); !reflect.DeepEqual(val, val1) {
    97  		t.Errorf("validator mismatch: have %v, want %v", val, val1)
    98  	}
    99  	// test get by invalid index
   100  	if val := valSet.GetByIndex(uint64(2)); val != nil {
   101  		t.Errorf("validator mismatch: have %v, want nil", val)
   102  	}
   103  	// test get by address
   104  	if _, val := valSet.GetByAddress(addr2); !reflect.DeepEqual(val, val2) {
   105  		t.Errorf("validator mismatch: have %v, want %v", val, val2)
   106  	}
   107  	// test get by invalid address
   108  	invalidAddr := common.HexToAddress("0x9535b2e7faaba5288511d89341d94a38063a349b")
   109  	if _, val := valSet.GetByAddress(invalidAddr); val != nil {
   110  		t.Errorf("validator mismatch: have %v, want nil", val)
   111  	}
   112  	// test get proposer
   113  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   114  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   115  	}
   116  	// test calculate proposer
   117  	lastProposer := addr1
   118  	valSet.CalcProposer(lastProposer, uint64(0))
   119  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   120  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   121  	}
   122  	valSet.CalcProposer(lastProposer, uint64(3))
   123  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   124  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   125  	}
   126  	// test empty last proposer
   127  	lastProposer = common.Address{}
   128  	valSet.CalcProposer(lastProposer, uint64(3))
   129  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   130  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   131  	}
   132  }
   133  
   134  func TestEmptyValSet(t *testing.T) {
   135  	valSet := NewSet(ExtractValidators([]byte{}), istanbul.RoundRobin)
   136  	if valSet == nil {
   137  		t.Errorf("validator set should not be nil")
   138  	}
   139  }
   140  
   141  func TestAddAndRemoveValidator(t *testing.T) {
   142  	valSet := NewSet(ExtractValidators([]byte{}), istanbul.RoundRobin)
   143  	if !valSet.AddValidator(common.StringToAddress(string(rune(2)))) {
   144  		t.Error("the validator should be added")
   145  	}
   146  	if valSet.AddValidator(common.StringToAddress(string(rune(2)))) {
   147  		t.Error("the existing validator should not be added")
   148  	}
   149  	valSet.AddValidator(common.StringToAddress(string(rune(1))))
   150  	valSet.AddValidator(common.StringToAddress(string(rune(0))))
   151  	if len(valSet.List()) != 3 {
   152  		t.Error("the size of validator set should be 3")
   153  	}
   154  
   155  	for i, v := range valSet.List() {
   156  		expected := common.StringToAddress(string(rune(i)))
   157  		if v.Address() != expected {
   158  			t.Errorf("the order of validators is wrong: have %v, want %v", v.Address().Hex(), expected.Hex())
   159  		}
   160  	}
   161  
   162  	if !valSet.RemoveValidator(common.StringToAddress(string(rune(2)))) {
   163  		t.Error("the validator should be removed")
   164  	}
   165  	if valSet.RemoveValidator(common.StringToAddress(string(rune(2)))) {
   166  		t.Error("the non-existing validator should not be removed")
   167  	}
   168  	if len(valSet.List()) != 2 {
   169  		t.Error("the size of validator set should be 2")
   170  	}
   171  	valSet.RemoveValidator(common.StringToAddress(string(rune(1))))
   172  	if len(valSet.List()) != 1 {
   173  		t.Error("the size of validator set should be 1")
   174  	}
   175  	valSet.RemoveValidator(common.StringToAddress(string(rune(0))))
   176  	if len(valSet.List()) != 0 {
   177  		t.Error("the size of validator set should be 0")
   178  	}
   179  }
   180  
   181  func TestStickyProposer(t *testing.T) {
   182  	b1 := common.Hex2Bytes(testAddress)
   183  	b2 := common.Hex2Bytes(testAddress2)
   184  	addr1 := common.BytesToAddress(b1)
   185  	addr2 := common.BytesToAddress(b2)
   186  	val1 := New(addr1)
   187  	val2 := New(addr2)
   188  
   189  	valSet := newDefaultSet([]common.Address{addr1, addr2}, istanbul.Sticky)
   190  
   191  	// test get proposer
   192  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   193  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   194  	}
   195  	// test calculate proposer
   196  	lastProposer := addr1
   197  	valSet.CalcProposer(lastProposer, uint64(0))
   198  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val1) {
   199  		t.Errorf("proposer mismatch: have %v, want %v", val, val1)
   200  	}
   201  
   202  	valSet.CalcProposer(lastProposer, uint64(1))
   203  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   204  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   205  	}
   206  	// test empty last proposer
   207  	lastProposer = common.Address{}
   208  	valSet.CalcProposer(lastProposer, uint64(3))
   209  	if val := valSet.GetProposer(); !reflect.DeepEqual(val, val2) {
   210  		t.Errorf("proposer mismatch: have %v, want %v", val, val2)
   211  	}
   212  }
   213  
   214  func TestDefaultSet_SubList(t *testing.T) {
   215  	fork.SetHardForkBlockNumberConfig(&params.ChainConfig{})
   216  	defer fork.ClearHardForkBlockNumberConfig()
   217  
   218  	b1 := common.Hex2Bytes(testAddress)
   219  	b2 := common.Hex2Bytes(testAddress2)
   220  	b3 := common.Hex2Bytes(testAddress3)
   221  	b4 := common.Hex2Bytes(testAddress4)
   222  	b5 := common.Hex2Bytes(testAddress5)
   223  	addr1 := common.BytesToAddress(b1)
   224  	addr2 := common.BytesToAddress(b2)
   225  	addr3 := common.BytesToAddress(b3)
   226  	addr4 := common.BytesToAddress(b4)
   227  	addr5 := common.BytesToAddress(b5)
   228  	testAddresses := []common.Address{addr1, addr2, addr3, addr4, addr5}
   229  
   230  	valSet := NewSet(testAddresses, istanbul.RoundRobin)
   231  	if valSet == nil {
   232  		t.Errorf("the format of validator set is invalid")
   233  		t.FailNow()
   234  	}
   235  	valSet.SetSubGroupSize(3)
   236  
   237  	hash := istanbul.RLPHash("This is a test hash")
   238  	view := &istanbul.View{
   239  		Sequence: new(big.Int).SetInt64(1),
   240  		Round:    new(big.Int).SetInt64(0),
   241  	}
   242  
   243  	lenAddress := len(testAddresses)
   244  	for i := 0; i < lenAddress*2; i++ {
   245  		currentProposer := valSet.GetProposer()
   246  		assert.Equal(t, testAddresses[i%lenAddress], currentProposer.Address())
   247  
   248  		committee := valSet.SubList(hash, view)
   249  
   250  		assert.Equal(t, testAddresses[i%lenAddress].String(), committee[0].String())
   251  		assert.Equal(t, testAddresses[(i+1)%lenAddress].String(), committee[1].String())
   252  
   253  		valSet.CalcProposer(currentProposer.Address(), view.Round.Uint64())
   254  	}
   255  }
   256  
   257  func TestDefaultSet_Copy(t *testing.T) {
   258  	b1 := common.Hex2Bytes(testAddress)
   259  	b2 := common.Hex2Bytes(testAddress2)
   260  	b3 := common.Hex2Bytes(testAddress3)
   261  	b4 := common.Hex2Bytes(testAddress4)
   262  	b5 := common.Hex2Bytes(testAddress5)
   263  	addr1 := common.BytesToAddress(b1)
   264  	addr2 := common.BytesToAddress(b2)
   265  	addr3 := common.BytesToAddress(b3)
   266  	addr4 := common.BytesToAddress(b4)
   267  	addr5 := common.BytesToAddress(b5)
   268  	testAddresses := []common.Address{addr1, addr2, addr3, addr4, addr5}
   269  
   270  	valSet := NewSet(testAddresses, istanbul.RoundRobin)
   271  	copiedValSet := valSet.Copy()
   272  
   273  	assert.NotEqual(t, fmt.Sprintf("%p", &valSet), fmt.Sprintf("%p", &copiedValSet))
   274  
   275  	assert.Equal(t, valSet.List(), copiedValSet.List())
   276  	assert.NotEqual(t, fmt.Sprintf("%p", valSet.List()), fmt.Sprintf("%p", copiedValSet.List()))
   277  
   278  	for i := uint64(0); i < valSet.Size(); i++ {
   279  		assert.Equal(t, valSet.List()[i], copiedValSet.List()[i])
   280  		assert.NotEqual(t, fmt.Sprintf("%p", valSet.List()[i]), fmt.Sprintf("%p", copiedValSet.List())[i])
   281  	}
   282  
   283  	assert.Equal(t, valSet.GetProposer(), copiedValSet.GetProposer())
   284  	assert.NotEqual(t, fmt.Sprintf("%p", valSet.GetProposer()), fmt.Sprintf("%p", copiedValSet.GetProposer()))
   285  
   286  	assert.Equal(t, valSet.Policy(), copiedValSet.Policy())
   287  	assert.Equal(t, valSet.SubGroupSize(), copiedValSet.SubGroupSize())
   288  	assert.Equal(t, valSet.TotalVotingPower(), copiedValSet.TotalVotingPower())
   289  }