github.com/aakash4dev/cometbft@v0.38.2/types/validation_test.go (about) 1 package types 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 10 cmtmath "github.com/aakash4dev/cometbft/libs/math" 11 cmtproto "github.com/aakash4dev/cometbft/proto/tendermint/types" 12 ) 13 14 // Check VerifyCommit, VerifyCommitLight and VerifyCommitLightTrusting basic 15 // verification. 16 func TestValidatorSet_VerifyCommit_All(t *testing.T) { 17 var ( 18 round = int32(0) 19 height = int64(100) 20 21 blockID = makeBlockID([]byte("blockhash"), 1000, []byte("partshash")) 22 chainID = "Lalande21185" 23 trustLevel = cmtmath.Fraction{Numerator: 2, Denominator: 3} 24 ) 25 26 testCases := []struct { 27 description string 28 // vote chainID 29 chainID string 30 // vote blockID 31 blockID BlockID 32 valSize int 33 34 // height of the commit 35 height int64 36 37 // votes 38 blockVotes int 39 nilVotes int 40 absentVotes int 41 42 expErr bool 43 }{ 44 {"good (batch verification)", chainID, blockID, 3, height, 3, 0, 0, false}, 45 {"good (single verification)", chainID, blockID, 1, height, 1, 0, 0, false}, 46 47 {"wrong signature (#0)", "EpsilonEridani", blockID, 2, height, 2, 0, 0, true}, 48 {"wrong block ID", chainID, makeBlockIDRandom(), 2, height, 2, 0, 0, true}, 49 {"wrong height", chainID, blockID, 1, height - 1, 1, 0, 0, true}, 50 51 {"wrong set size: 4 vs 3", chainID, blockID, 4, height, 3, 0, 0, true}, 52 {"wrong set size: 1 vs 2", chainID, blockID, 1, height, 2, 0, 0, true}, 53 54 {"insufficient voting power: got 30, needed more than 66", chainID, blockID, 10, height, 3, 2, 5, true}, 55 {"insufficient voting power: got 0, needed more than 6", chainID, blockID, 1, height, 0, 0, 1, true}, 56 {"insufficient voting power: got 60, needed more than 60", chainID, blockID, 9, height, 6, 3, 0, true}, 57 } 58 59 for _, tc := range testCases { 60 tc := tc 61 t.Run(tc.description, func(t *testing.T) { 62 _, valSet, vals := randVoteSet(tc.height, round, cmtproto.PrecommitType, tc.valSize, 10, false) 63 totalVotes := tc.blockVotes + tc.absentVotes + tc.nilVotes 64 sigs := make([]CommitSig, totalVotes) 65 vi := 0 66 // add absent sigs first 67 for i := 0; i < tc.absentVotes; i++ { 68 sigs[vi] = NewCommitSigAbsent() 69 vi++ 70 } 71 for i := 0; i < tc.blockVotes+tc.nilVotes; i++ { 72 73 pubKey, err := vals[vi%len(vals)].GetPubKey() 74 require.NoError(t, err) 75 vote := &Vote{ 76 ValidatorAddress: pubKey.Address(), 77 ValidatorIndex: int32(vi), 78 Height: tc.height, 79 Round: round, 80 Type: cmtproto.PrecommitType, 81 BlockID: tc.blockID, 82 Timestamp: time.Now(), 83 } 84 if i >= tc.blockVotes { 85 vote.BlockID = BlockID{} 86 } 87 88 v := vote.ToProto() 89 90 require.NoError(t, vals[vi%len(vals)].SignVote(tc.chainID, v)) 91 vote.Signature = v.Signature 92 93 sigs[vi] = vote.CommitSig() 94 95 vi++ 96 } 97 commit := &Commit{ 98 Height: tc.height, 99 Round: round, 100 BlockID: tc.blockID, 101 Signatures: sigs, 102 } 103 104 err := valSet.VerifyCommit(chainID, blockID, height, commit) 105 if tc.expErr { 106 if assert.Error(t, err, "VerifyCommit") { 107 assert.Contains(t, err.Error(), tc.description, "VerifyCommit") 108 } 109 } else { 110 assert.NoError(t, err, "VerifyCommit") 111 } 112 113 err = valSet.VerifyCommitLight(chainID, blockID, height, commit) 114 if tc.expErr { 115 if assert.Error(t, err, "VerifyCommitLight") { 116 assert.Contains(t, err.Error(), tc.description, "VerifyCommitLight") 117 } 118 } else { 119 assert.NoError(t, err, "VerifyCommitLight") 120 } 121 122 // only a subsection of the tests apply to VerifyCommitLightTrusting 123 if totalVotes != tc.valSize || !tc.blockID.Equals(blockID) || tc.height != height { 124 tc.expErr = false 125 } 126 err = valSet.VerifyCommitLightTrusting(chainID, commit, trustLevel) 127 if tc.expErr { 128 if assert.Error(t, err, "VerifyCommitLightTrusting") { 129 assert.Contains(t, err.Error(), tc.description, "VerifyCommitLightTrusting") 130 } 131 } else { 132 assert.NoError(t, err, "VerifyCommitLightTrusting") 133 } 134 }) 135 } 136 } 137 138 func TestValidatorSet_VerifyCommit_CheckAllSignatures(t *testing.T) { 139 var ( 140 chainID = "test_chain_id" 141 h = int64(3) 142 blockID = makeBlockIDRandom() 143 ) 144 145 voteSet, valSet, vals := randVoteSet(h, 0, cmtproto.PrecommitType, 4, 10, false) 146 extCommit, err := MakeExtCommit(blockID, h, 0, voteSet, vals, time.Now(), false) 147 require.NoError(t, err) 148 commit := extCommit.ToCommit() 149 require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit)) 150 151 // malleate 4th signature 152 vote := voteSet.GetByIndex(3) 153 v := vote.ToProto() 154 err = vals[3].SignVote("CentaurusA", v) 155 require.NoError(t, err) 156 vote.Signature = v.Signature 157 vote.ExtensionSignature = v.ExtensionSignature 158 commit.Signatures[3] = vote.CommitSig() 159 160 err = valSet.VerifyCommit(chainID, blockID, h, commit) 161 if assert.Error(t, err) { 162 assert.Contains(t, err.Error(), "wrong signature (#3)") 163 } 164 } 165 166 func TestValidatorSet_VerifyCommitLight_ReturnsAsSoonAsMajorityOfVotingPowerSigned(t *testing.T) { 167 var ( 168 chainID = "test_chain_id" 169 h = int64(3) 170 blockID = makeBlockIDRandom() 171 ) 172 173 voteSet, valSet, vals := randVoteSet(h, 0, cmtproto.PrecommitType, 4, 10, false) 174 extCommit, err := MakeExtCommit(blockID, h, 0, voteSet, vals, time.Now(), false) 175 require.NoError(t, err) 176 commit := extCommit.ToCommit() 177 require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit)) 178 179 // malleate 4th signature (3 signatures are enough for 2/3+) 180 vote := voteSet.GetByIndex(3) 181 v := vote.ToProto() 182 err = vals[3].SignVote("CentaurusA", v) 183 require.NoError(t, err) 184 vote.Signature = v.Signature 185 vote.ExtensionSignature = v.ExtensionSignature 186 commit.Signatures[3] = vote.CommitSig() 187 188 err = valSet.VerifyCommitLight(chainID, blockID, h, commit) 189 assert.NoError(t, err) 190 } 191 192 func TestValidatorSet_VerifyCommitLightTrusting_ReturnsAsSoonAsTrustLevelOfVotingPowerSigned(t *testing.T) { 193 var ( 194 chainID = "test_chain_id" 195 h = int64(3) 196 blockID = makeBlockIDRandom() 197 ) 198 199 voteSet, valSet, vals := randVoteSet(h, 0, cmtproto.PrecommitType, 4, 10, false) 200 extCommit, err := MakeExtCommit(blockID, h, 0, voteSet, vals, time.Now(), false) 201 require.NoError(t, err) 202 commit := extCommit.ToCommit() 203 require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit)) 204 205 // malleate 3rd signature (2 signatures are enough for 1/3+ trust level) 206 vote := voteSet.GetByIndex(2) 207 v := vote.ToProto() 208 err = vals[2].SignVote("CentaurusA", v) 209 require.NoError(t, err) 210 vote.Signature = v.Signature 211 vote.ExtensionSignature = v.ExtensionSignature 212 commit.Signatures[2] = vote.CommitSig() 213 214 err = valSet.VerifyCommitLightTrusting(chainID, commit, cmtmath.Fraction{Numerator: 1, Denominator: 3}) 215 assert.NoError(t, err) 216 } 217 218 func TestValidatorSet_VerifyCommitLightTrusting(t *testing.T) { 219 var ( 220 blockID = makeBlockIDRandom() 221 voteSet, originalValset, vals = randVoteSet(1, 1, cmtproto.PrecommitType, 6, 1, false) 222 extCommit, err = MakeExtCommit(blockID, 1, 1, voteSet, vals, time.Now(), false) 223 newValSet, _ = RandValidatorSet(2, 1) 224 ) 225 require.NoError(t, err) 226 commit := extCommit.ToCommit() 227 228 testCases := []struct { 229 valSet *ValidatorSet 230 err bool 231 }{ 232 // good 233 0: { 234 valSet: originalValset, 235 err: false, 236 }, 237 // bad - no overlap between validator sets 238 1: { 239 valSet: newValSet, 240 err: true, 241 }, 242 // good - first two are different but the rest of the same -> >1/3 243 2: { 244 valSet: NewValidatorSet(append(newValSet.Validators, originalValset.Validators...)), 245 err: false, 246 }, 247 } 248 249 for _, tc := range testCases { 250 err = tc.valSet.VerifyCommitLightTrusting("test_chain_id", commit, 251 cmtmath.Fraction{Numerator: 1, Denominator: 3}) 252 if tc.err { 253 assert.Error(t, err) 254 } else { 255 assert.NoError(t, err) 256 } 257 } 258 } 259 260 func TestValidatorSet_VerifyCommitLightTrustingErrorsOnOverflow(t *testing.T) { 261 var ( 262 blockID = makeBlockIDRandom() 263 voteSet, valSet, vals = randVoteSet(1, 1, cmtproto.PrecommitType, 1, MaxTotalVotingPower, false) 264 extCommit, err = MakeExtCommit(blockID, 1, 1, voteSet, vals, time.Now(), false) 265 ) 266 require.NoError(t, err) 267 268 err = valSet.VerifyCommitLightTrusting("test_chain_id", extCommit.ToCommit(), 269 cmtmath.Fraction{Numerator: 25, Denominator: 55}) 270 if assert.Error(t, err) { 271 assert.Contains(t, err.Error(), "int64 overflow") 272 } 273 }