github.com/klaytn/klaytn@v1.12.1/consensus/istanbul/core/vrank_test.go (about)

     1  // Copyright 2023 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 core
    18  
    19  import (
    20  	"encoding/hex"
    21  	"math/big"
    22  	"sort"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/klaytn/klaytn/common"
    27  	"github.com/klaytn/klaytn/consensus/istanbul"
    28  	"github.com/klaytn/klaytn/consensus/istanbul/validator"
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func genCommitteeFromAddrs(addrs []common.Address) istanbul.Validators {
    33  	committee := []istanbul.Validator{}
    34  	for _, addr := range addrs {
    35  		committee = append(committee, validator.New(addr))
    36  	}
    37  	return committee
    38  }
    39  
    40  func TestVrank(t *testing.T) {
    41  	var (
    42  		N         = 6
    43  		quorum    = 4
    44  		addrs, _  = genValidators(N)
    45  		committee = genCommitteeFromAddrs(addrs)
    46  		view      = istanbul.View{Sequence: big.NewInt(0), Round: big.NewInt(0)}
    47  		msg       = &istanbul.Subject{View: &view}
    48  		vrank     = NewVrank(view, committee)
    49  
    50  		expectedAssessList  []uint8
    51  		expectedLateCommits []time.Duration
    52  	)
    53  
    54  	sort.Sort(committee)
    55  	for i := 0; i < quorum; i++ {
    56  		vrank.AddCommit(msg, committee[i])
    57  		expectedAssessList = append(expectedAssessList, vrankArrivedEarly)
    58  	}
    59  	vrank.HandleCommitted(view.Sequence)
    60  	for i := quorum; i < N; i++ {
    61  		vrank.AddCommit(msg, committee[i])
    62  		expectedAssessList = append(expectedAssessList, vrankArrivedLate)
    63  		expectedLateCommits = append(expectedLateCommits, vrank.commitArrivalTimeMap[committee[i].Address()])
    64  	}
    65  
    66  	bitmap, late := vrank.Bitmap(), vrank.LateCommits()
    67  	assert.Equal(t, hex.EncodeToString(compress(expectedAssessList)), bitmap)
    68  	assert.Equal(t, expectedLateCommits, late)
    69  }
    70  
    71  func TestVrankAssessBatch(t *testing.T) {
    72  	arr := []time.Duration{0, 4, 1, vrankNotArrivedPlaceholder, 2}
    73  	threshold := time.Duration(2)
    74  	expected := []uint8{
    75  		vrankArrivedEarly, vrankArrivedLate, vrankArrivedEarly, vrankNotArrived, vrankArrivedEarly,
    76  	}
    77  	assert.Equal(t, expected, assessBatch(arr, threshold))
    78  }
    79  
    80  func TestVrankSerialize(t *testing.T) {
    81  	var (
    82  		N         = 6
    83  		addrs, _  = genValidators(N)
    84  		committee = genCommitteeFromAddrs(addrs)
    85  		timeMap   = make(map[common.Address]time.Duration)
    86  		expected  = make([]time.Duration, len(addrs))
    87  	)
    88  
    89  	sort.Sort(committee)
    90  	for i, val := range committee {
    91  		t := time.Duration((i * 100) * int(time.Millisecond))
    92  		timeMap[val.Address()] = t
    93  		expected[i] = t
    94  	}
    95  
    96  	assert.Equal(t, expected, serialize(committee, timeMap))
    97  }
    98  
    99  func TestVrankCompress(t *testing.T) {
   100  	tcs := []struct {
   101  		input    []uint8
   102  		expected []byte
   103  	}{
   104  		{
   105  			input:    []uint8{2},
   106  			expected: []byte{0b10_000000},
   107  		},
   108  		{
   109  			input:    []uint8{2, 1},
   110  			expected: []byte{0b10_01_0000},
   111  		},
   112  		{
   113  			input:    []uint8{0, 2, 1},
   114  			expected: []byte{0b00_10_01_00},
   115  		},
   116  		{
   117  			input:    []uint8{0, 2, 1, 1},
   118  			expected: []byte{0b00_10_01_01},
   119  		},
   120  		{
   121  			input:    []uint8{1, 2, 1, 2, 1},
   122  			expected: []byte{0b01_10_01_10, 0b01_000000},
   123  		},
   124  		{
   125  			input:    []uint8{1, 2, 1, 2, 1, 2},
   126  			expected: []byte{0b01_10_01_10, 0b01_10_0000},
   127  		},
   128  		{
   129  			input:    []uint8{1, 2, 1, 2, 1, 2, 1},
   130  			expected: []byte{0b01_10_01_10, 0b01_10_01_00},
   131  		},
   132  		{
   133  			input:    []uint8{1, 2, 1, 2, 1, 2, 0, 2},
   134  			expected: []byte{0b01_10_01_10, 0b01_10_00_10},
   135  		},
   136  		{
   137  			input:    []uint8{1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1},
   138  			expected: []byte{0b01011010, 0b01011010, 0b01011010, 0b01011010, 0b01010000},
   139  		},
   140  	}
   141  	for i, tc := range tcs {
   142  		assert.Equal(t, tc.expected, compress(tc.input), "tc %d failed", i)
   143  	}
   144  }