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

     1  package core
     2  
     3  import (
     4  	"math/big"
     5  	"math/rand"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/golang/mock/gomock"
    11  	"github.com/klaytn/klaytn/blockchain/types"
    12  	"github.com/klaytn/klaytn/common"
    13  	"github.com/klaytn/klaytn/consensus/istanbul"
    14  	mock_istanbul "github.com/klaytn/klaytn/consensus/istanbul/mocks"
    15  	"github.com/klaytn/klaytn/fork"
    16  	"github.com/klaytn/klaytn/params"
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  func TestCore_sendPrepare(t *testing.T) {
    21  	fork.SetHardForkBlockNumberConfig(&params.ChainConfig{})
    22  	defer fork.ClearHardForkBlockNumberConfig()
    23  
    24  	validatorAddrs, validatorKeyMap := genValidators(6)
    25  	mockBackend, mockCtrl := newMockBackend(t, validatorAddrs)
    26  
    27  	istConfig := istanbul.DefaultConfig
    28  	istConfig.ProposerPolicy = istanbul.WeightedRandom
    29  
    30  	istCore := New(mockBackend, istConfig).(*core)
    31  	if err := istCore.Start(); err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	defer istCore.Stop()
    35  
    36  	lastProposal, lastProposer := mockBackend.LastProposal()
    37  	proposal, err := genBlock(lastProposal.(*types.Block), validatorKeyMap[validatorAddrs[0]])
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	istCore.current.Preprepare = &istanbul.Preprepare{
    43  		View:     istCore.currentView(),
    44  		Proposal: proposal,
    45  	}
    46  
    47  	mockCtrl.Finish()
    48  
    49  	// invalid case - not committee
    50  	{
    51  		// Increase round number until the owner of istanbul.core is not a member of the committee
    52  		for istCore.valSet.CheckInSubList(lastProposal.Hash(), istCore.currentView(), istCore.Address()) {
    53  			istCore.current.round.Add(istCore.current.round, common.Big1)
    54  			istCore.valSet.CalcProposer(lastProposer, istCore.current.round.Uint64())
    55  		}
    56  
    57  		mockCtrl := gomock.NewController(t)
    58  		mockBackend := mock_istanbul.NewMockBackend(mockCtrl)
    59  		mockBackend.EXPECT().Sign(gomock.Any()).Return(nil, nil).Times(0)
    60  		mockBackend.EXPECT().Broadcast(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(0)
    61  
    62  		istCore.backend = mockBackend
    63  		istCore.sendPrepare()
    64  
    65  		// methods of mockBackend should be executed given times
    66  		mockCtrl.Finish()
    67  	}
    68  
    69  	// valid case
    70  	{
    71  		// Increase round number until the owner of istanbul.core become a member of the committee
    72  		for !istCore.valSet.CheckInSubList(lastProposal.Hash(), istCore.currentView(), istCore.Address()) {
    73  			istCore.current.round.Add(istCore.current.round, common.Big1)
    74  			istCore.valSet.CalcProposer(lastProposer, istCore.current.round.Uint64())
    75  		}
    76  
    77  		mockCtrl := gomock.NewController(t)
    78  		mockBackend := mock_istanbul.NewMockBackend(mockCtrl)
    79  		mockBackend.EXPECT().Sign(gomock.Any()).Return(nil, nil).Times(1)
    80  		mockBackend.EXPECT().Broadcast(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1)
    81  
    82  		istCore.backend = mockBackend
    83  		istCore.sendPrepare()
    84  
    85  		// methods of mockBackend should be executed given times
    86  		mockCtrl.Finish()
    87  	}
    88  }
    89  
    90  func BenchmarkMsgCmp(b *testing.B) {
    91  	getEmptySubject := func() istanbul.Subject {
    92  		return istanbul.Subject{
    93  			View: &istanbul.View{
    94  				Round:    big.NewInt(0),
    95  				Sequence: big.NewInt(0),
    96  			},
    97  			Digest:   common.HexToHash("1"),
    98  			PrevHash: common.HexToHash("2"),
    99  		}
   100  	}
   101  	s1, s2 := getEmptySubject(), getEmptySubject()
   102  
   103  	// Worst
   104  	b.Run("reflect.DeepEqual", func(b *testing.B) {
   105  		for i := 0; i < b.N; i++ {
   106  			reflect.DeepEqual(s1, s2)
   107  		}
   108  	})
   109  
   110  	// Better
   111  	b.Run("EqualImpl", func(b *testing.B) {
   112  		for i := 0; i < b.N; i++ {
   113  			s1.Equal(&s2)
   114  		}
   115  	})
   116  }
   117  
   118  func TestSubjectCmp(t *testing.T) {
   119  	genRandomHash := func(n int) common.Hash {
   120  		b := make([]byte, n)
   121  		_, err := rand.Read(b)
   122  		assert.Nil(t, err)
   123  		return common.BytesToHash(b)
   124  	}
   125  	genRandomInt := func(min, max int) int64 {
   126  		return int64(rand.Intn(max-min) + min)
   127  	}
   128  	genSubject := func(min, max int) *istanbul.Subject {
   129  		round, seq := big.NewInt(genRandomInt(min, max)), big.NewInt(genRandomInt(min, max))
   130  		digest, prevHash := genRandomHash(max), genRandomHash(max)
   131  		return &istanbul.Subject{
   132  			View: &istanbul.View{
   133  				Round:    round,
   134  				Sequence: seq,
   135  			},
   136  			Digest:   digest,
   137  			PrevHash: prevHash,
   138  		}
   139  	}
   140  	copySubject := func(s *istanbul.Subject) *istanbul.Subject {
   141  		r := new(istanbul.Subject)
   142  		v := new(istanbul.View)
   143  		r.Digest = s.Digest
   144  		r.PrevHash = s.PrevHash
   145  		v.Round = new(big.Int).SetUint64(s.View.Round.Uint64())
   146  		v.Sequence = new(big.Int).SetUint64(s.View.Sequence.Uint64())
   147  		r.View = v
   148  		return r
   149  	}
   150  
   151  	rand.Seed(time.Now().UnixNano())
   152  	min, max, n := 1, 9999, 10000
   153  	var identity bool
   154  	var s1, s2 *istanbul.Subject
   155  	for i := 0; i < n; i++ {
   156  		s1 = genSubject(min, max)
   157  		if rand.Intn(2) == 0 {
   158  			identity = true
   159  			s2 = copySubject(s1)
   160  		} else {
   161  			identity = false
   162  			s2 = genSubject(max+1, max*2)
   163  		}
   164  		e := s1.Equal(s2)
   165  		if identity {
   166  			assert.Equal(t, e, true)
   167  		} else {
   168  			assert.Equal(t, e, false)
   169  		}
   170  		assert.Equal(t, e, reflect.DeepEqual(s1, s2))
   171  	}
   172  }
   173  
   174  func TestNilSubjectCmp(t *testing.T) {
   175  	sbj := istanbul.Subject{
   176  		View: &istanbul.View{
   177  			Round:    big.NewInt(0),
   178  			Sequence: big.NewInt(0),
   179  		},
   180  		Digest:   common.HexToHash("1"),
   181  		PrevHash: common.HexToHash("2"),
   182  	}
   183  	var nilSbj *istanbul.Subject = nil
   184  
   185  	assert.Equal(t, sbj.Equal(nil), false)
   186  	assert.Equal(t, sbj.Equal(nilSbj), false)
   187  	assert.Equal(t, nilSbj.Equal(&sbj), false)
   188  	assert.Equal(t, nilSbj.Equal(nilSbj), true)
   189  	assert.Equal(t, nilSbj.Equal(nil), true)
   190  }