github.com/iotexproject/iotex-core@v1.14.1-rc1/consensus/scheme/rolldpos/endorsementmanager_test.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package rolldpos 7 8 import ( 9 "testing" 10 "time" 11 12 "github.com/golang/mock/gomock" 13 "github.com/iotexproject/iotex-core/blockchain/block" 14 "github.com/stretchr/testify/require" 15 16 "github.com/iotexproject/iotex-core/endorsement" 17 "github.com/iotexproject/iotex-core/pkg/log" 18 "github.com/iotexproject/iotex-core/test/identityset" 19 ) 20 21 func TestEndorserEndorsementCollection(t *testing.T) { 22 require := require.New(t) 23 ctrl := gomock.NewController(t) 24 defer ctrl.Finish() 25 now := time.Now() 26 priKey := identityset.PrivateKey(0) 27 mockProposal := endorsement.NewEndorsement( 28 now.Add(-2*time.Second), 29 priKey.PublicKey(), 30 []byte{}, 31 ) 32 mockLock := endorsement.NewEndorsement( 33 now.Add(-2*time.Second), 34 priKey.PublicKey(), 35 []byte{}, 36 ) 37 mockCommit := endorsement.NewEndorsement( 38 now.Add(-2*time.Second), 39 priKey.PublicKey(), 40 []byte{}, 41 ) 42 eec := newEndorserEndorsementCollection() 43 require.NoError(eec.AddEndorsement(PROPOSAL, mockProposal)) 44 require.NoError(eec.AddEndorsement(LOCK, mockLock)) 45 require.NoError(eec.AddEndorsement(COMMIT, mockCommit)) 46 t.Run("read", func(t *testing.T) { 47 require.Equal(mockProposal, eec.Endorsement(PROPOSAL)) 48 require.Equal(mockLock, eec.Endorsement(LOCK)) 49 require.Equal(mockCommit, eec.Endorsement(COMMIT)) 50 }) 51 t.Run("cleanup", func(t *testing.T) { 52 cleaned := eec.Cleanup(now) 53 require.Nil(cleaned.Endorsement(PROPOSAL)) 54 require.Nil(cleaned.Endorsement(LOCK)) 55 require.NotNil(cleaned.Endorsement(COMMIT)) 56 }) 57 t.Run("failure-to-replace", func(t *testing.T) { 58 mockProposal2 := endorsement.NewEndorsement( 59 now.Add(-3*time.Second), 60 priKey.PublicKey(), 61 []byte{}, 62 ) 63 require.Error(eec.AddEndorsement(PROPOSAL, mockProposal2)) 64 }) 65 t.Run("success-to-replace", func(t *testing.T) { 66 mockProposal2 := endorsement.NewEndorsement( 67 now.Add(-2*time.Second), 68 priKey.PublicKey(), 69 []byte{}, 70 ) 71 require.NoError(eec.AddEndorsement(PROPOSAL, mockProposal2)) 72 }) 73 } 74 75 func TestBlockEndorsementCollection(t *testing.T) { 76 require := require.New(t) 77 b := getBlock(t) 78 ec := newBlockEndorsementCollection(&b) 79 require.NotNil(ec) 80 require.NoError(ec.SetBlock(&b)) 81 require.Equal(&b, ec.Block()) 82 end := endorsement.NewEndorsement(time.Now(), b.PublicKey(), []byte("123")) 83 84 require.NoError(ec.AddEndorsement(PROPOSAL, end)) 85 require.Equal(end, ec.Endorsement(b.PublicKey().HexString(), PROPOSAL)) 86 ends := ec.Endorsements([]ConsensusVoteTopic{PROPOSAL}) 87 require.Equal(1, len(ends)) 88 require.Equal(end, ends[0]) 89 90 ec = ec.Cleanup(time.Now().Add(time.Second * 10 * -1)) 91 require.Equal(1, len(ec.endorsers)) 92 require.Equal(1, len(ec.endorsers[b.PublicKey().HexString()].endorsements)) 93 require.Equal(end, ec.endorsers[b.PublicKey().HexString()].Endorsement(PROPOSAL)) 94 } 95 96 func TestEndorsementManager(t *testing.T) { 97 require := require.New(t) 98 99 em, err := newEndorsementManager(nil, block.NewDeserializer(0)) 100 require.NoError(err) 101 require.NotNil(em) 102 require.Equal(0, em.Size()) 103 require.Equal(0, em.SizeWithBlock()) 104 105 b := getBlock(t) 106 107 require.NoError(em.RegisterBlock(&b)) 108 109 require.Panics(func() { 110 em.AddVoteEndorsement(nil, nil) 111 }, "vote is nil") 112 blkHash := b.HashBlock() 113 cv := NewConsensusVote(blkHash[:], PROPOSAL) 114 require.NotNil(cv) 115 116 require.Panics(func() { 117 em.AddVoteEndorsement(cv, nil) 118 }, "endorsement is nil") 119 120 timestamp := time.Now() 121 end := endorsement.NewEndorsement(timestamp, b.PublicKey(), []byte("123")) 122 require.NoError(em.AddVoteEndorsement(cv, end)) 123 124 require.Panics(func() { 125 em.Log(nil, nil) 126 }, "logger is nil") 127 l := em.Log(log.L(), nil) 128 require.NotNil(l) 129 l.Info("test output") 130 131 cv2 := NewConsensusVote(blkHash[:], LOCK) 132 require.NotNil(cv2) 133 end2 := endorsement.NewEndorsement(timestamp.Add(time.Second*10), b.PublicKey(), []byte("456")) 134 require.NoError(em.AddVoteEndorsement(cv2, end2)) 135 l.Info("test output2") 136 137 encoded := encodeToString(cv.BlockHash()) 138 require.Equal(1, len(em.collections[encoded].endorsers)) 139 collection := em.collections[encoded].endorsers[end.Endorser().HexString()] 140 require.Equal(2, len(collection.endorsements)) 141 require.Equal(end, collection.endorsements[PROPOSAL]) 142 require.Equal(end2, collection.endorsements[LOCK]) 143 144 //cleanup 145 require.NoError(em.Cleanup(timestamp.Add(time.Second * 2))) 146 require.NotNil(em) 147 require.Equal(1, len(em.collections)) 148 require.Equal(1, len(em.collections[encoded].endorsers)) 149 150 collection = em.collections[encoded].endorsers[end.Endorser().HexString()] //ee 151 require.Equal(1, len(collection.endorsements)) 152 require.Equal(end2, collection.endorsements[LOCK]) 153 154 //when the time is zero, it should generate empty eManager 155 zerotime := time.Time{} 156 require.Equal(zerotime.IsZero(), true) 157 require.NoError(em.Cleanup(zerotime)) 158 require.Equal(0, len(em.collections)) 159 160 // test for cachedMintedBlock 161 require.NoError(em.SetMintedBlock(&b)) 162 require.Equal(&b, em.CachedMintedBlock()) 163 164 blkTimestamp := b.Timestamp() 165 require.NoError(em.Cleanup(blkTimestamp)) // if roundStartTime is same or ealier than blockTimestamp 166 require.NotNil(em) 167 require.NotNil(em.CachedMintedBlock()) // not clean up 168 require.Equal(&b, em.CachedMintedBlock()) 169 170 require.NoError(em.Cleanup(blkTimestamp.Add(time.Second * 2))) // if roundStartTime is after than blockTimestamp (old block) 171 require.Nil(em.CachedMintedBlock()) // clean up 172 173 require.NoError(em.SetMintedBlock(&b)) 174 require.Equal(&b, em.CachedMintedBlock()) 175 176 require.NoError(em.Cleanup(zerotime)) // if it is clean up with zero time 177 require.Nil(em.CachedMintedBlock()) // clean up 178 } 179 180 func TestEndorsementManagerProto(t *testing.T) { 181 require := require.New(t) 182 em, err := newEndorsementManager(nil, block.NewDeserializer(0)) 183 require.NoError(err) 184 require.NotNil(em) 185 186 b := getBlock(t) 187 188 require.NoError(em.RegisterBlock(&b)) 189 blkHash := b.HashBlock() 190 cv := NewConsensusVote(blkHash[:], PROPOSAL) 191 require.NotNil(cv) 192 end := endorsement.NewEndorsement(time.Now(), b.PublicKey(), []byte("123")) 193 require.NoError(em.AddVoteEndorsement(cv, end)) 194 require.Nil(em.cachedMintedBlk) 195 require.NoError(em.SetMintedBlock(&b)) 196 197 //test converting endorsement pb 198 endProto, err := end.Proto() 199 require.NoError(err) 200 end2 := &endorsement.Endorsement{} 201 require.NoError(end2.LoadProto(endProto)) 202 require.Equal(end, end2) 203 204 //test converting emanager pb 205 emProto, err := em.toProto() 206 require.NoError(err) 207 em2, err := newEndorsementManager(nil, block.NewDeserializer(0)) 208 require.NoError(err) 209 require.NoError(em2.fromProto(emProto, block.NewDeserializer(0))) 210 211 require.Equal(len(em.collections), len(em2.collections)) 212 encoded := encodeToString(cv.BlockHash()) 213 require.Equal(em.collections[encoded].endorsers, em2.collections[encoded].endorsers) 214 require.Equal(em.cachedMintedBlk.HashBlock(), em2.cachedMintedBlk.HashBlock()) 215 }