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  }