|
|
- package types
-
- import (
- "context"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- tmmath "github.com/tendermint/tendermint/libs/math"
- tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
- )
-
- // Check VerifyCommit, VerifyCommitLight and VerifyCommitLightTrusting basic
- // verification.
- func TestValidatorSet_VerifyCommit_All(t *testing.T) {
- var (
- round = int32(0)
- height = int64(100)
-
- blockID = makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
- chainID = "Lalande21185"
- trustLevel = tmmath.Fraction{Numerator: 2, Denominator: 3}
- )
-
- testCases := []struct {
- description string
- // vote chainID
- chainID string
- // vote blockID
- blockID BlockID
- valSize int
-
- // height of the commit
- height int64
-
- // votes
- blockVotes int
- nilVotes int
- absentVotes int
-
- expErr bool
- }{
- {"good (batch verification)", chainID, blockID, 3, height, 3, 0, 0, false},
- {"good (single verification)", chainID, blockID, 1, height, 1, 0, 0, false},
-
- {"wrong signature (#0)", "EpsilonEridani", blockID, 2, height, 2, 0, 0, true},
- {"wrong block ID", chainID, makeBlockIDRandom(), 2, height, 2, 0, 0, true},
- {"wrong height", chainID, blockID, 1, height - 1, 1, 0, 0, true},
-
- {"wrong set size: 4 vs 3", chainID, blockID, 4, height, 3, 0, 0, true},
- {"wrong set size: 1 vs 2", chainID, blockID, 1, height, 2, 0, 0, true},
-
- {"insufficient voting power: got 30, needed more than 66", chainID, blockID, 10, height, 3, 2, 5, true},
- {"insufficient voting power: got 0, needed more than 6", chainID, blockID, 1, height, 0, 0, 1, true},
- {"insufficient voting power: got 60, needed more than 60", chainID, blockID, 9, height, 6, 3, 0, true},
- }
-
- for _, tc := range testCases {
- tc := tc
- t.Run(tc.description, func(t *testing.T) {
- _, valSet, vals := randVoteSet(tc.height, round, tmproto.PrecommitType, tc.valSize, 10)
- totalVotes := tc.blockVotes + tc.absentVotes + tc.nilVotes
- sigs := make([]CommitSig, totalVotes)
- vi := 0
- // add absent sigs first
- for i := 0; i < tc.absentVotes; i++ {
- sigs[vi] = NewCommitSigAbsent()
- vi++
- }
- for i := 0; i < tc.blockVotes+tc.nilVotes; i++ {
-
- pubKey, err := vals[vi%len(vals)].GetPubKey(context.Background())
- require.NoError(t, err)
- vote := &Vote{
- ValidatorAddress: pubKey.Address(),
- ValidatorIndex: int32(vi),
- Height: tc.height,
- Round: round,
- Type: tmproto.PrecommitType,
- BlockID: tc.blockID,
- Timestamp: time.Now(),
- }
- if i >= tc.blockVotes {
- vote.BlockID = BlockID{}
- }
-
- v := vote.ToProto()
-
- require.NoError(t, vals[vi%len(vals)].SignVote(context.Background(), tc.chainID, v))
- vote.Signature = v.Signature
-
- sigs[vi] = vote.CommitSig()
-
- vi++
- }
- commit := NewCommit(tc.height, round, tc.blockID, sigs)
-
- err := valSet.VerifyCommit(chainID, blockID, height, commit)
- if tc.expErr {
- if assert.Error(t, err, "VerifyCommit") {
- assert.Contains(t, err.Error(), tc.description, "VerifyCommit")
- }
- } else {
- assert.NoError(t, err, "VerifyCommit")
- }
-
- err = valSet.VerifyCommitLight(chainID, blockID, height, commit)
- if tc.expErr {
- if assert.Error(t, err, "VerifyCommitLight") {
- assert.Contains(t, err.Error(), tc.description, "VerifyCommitLight")
- }
- } else {
- assert.NoError(t, err, "VerifyCommitLight")
- }
-
- // only a subsection of the tests apply to VerifyCommitLightTrusting
- if totalVotes != tc.valSize || !tc.blockID.Equals(blockID) || tc.height != height {
- tc.expErr = false
- }
- err = valSet.VerifyCommitLightTrusting(chainID, commit, trustLevel)
- if tc.expErr {
- if assert.Error(t, err, "VerifyCommitLightTrusting") {
- assert.Contains(t, err.Error(), tc.description, "VerifyCommitLightTrusting")
- }
- } else {
- assert.NoError(t, err, "VerifyCommitLightTrusting")
- }
- })
- }
- }
-
- func TestValidatorSet_VerifyCommit_CheckAllSignatures(t *testing.T) {
- var (
- chainID = "test_chain_id"
- h = int64(3)
- blockID = makeBlockIDRandom()
- )
-
- voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
- commit, err := makeCommit(blockID, h, 0, voteSet, vals, time.Now())
- require.NoError(t, err)
- require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit))
-
- // malleate 4th signature
- vote := voteSet.GetByIndex(3)
- v := vote.ToProto()
- err = vals[3].SignVote(context.Background(), "CentaurusA", v)
- require.NoError(t, err)
- vote.Signature = v.Signature
- commit.Signatures[3] = vote.CommitSig()
-
- err = valSet.VerifyCommit(chainID, blockID, h, commit)
- if assert.Error(t, err) {
- assert.Contains(t, err.Error(), "wrong signature (#3)")
- }
- }
-
- func TestValidatorSet_VerifyCommitLight_ReturnsAsSoonAsMajorityOfVotingPowerSigned(t *testing.T) {
- var (
- chainID = "test_chain_id"
- h = int64(3)
- blockID = makeBlockIDRandom()
- )
-
- voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
- commit, err := makeCommit(blockID, h, 0, voteSet, vals, time.Now())
- require.NoError(t, err)
- require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit))
-
- // malleate 4th signature (3 signatures are enough for 2/3+)
- vote := voteSet.GetByIndex(3)
- v := vote.ToProto()
- err = vals[3].SignVote(context.Background(), "CentaurusA", v)
- require.NoError(t, err)
- vote.Signature = v.Signature
- commit.Signatures[3] = vote.CommitSig()
-
- err = valSet.VerifyCommitLight(chainID, blockID, h, commit)
- assert.NoError(t, err)
- }
-
- func TestValidatorSet_VerifyCommitLightTrusting_ReturnsAsSoonAsTrustLevelOfVotingPowerSigned(t *testing.T) {
- var (
- chainID = "test_chain_id"
- h = int64(3)
- blockID = makeBlockIDRandom()
- )
-
- voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
- commit, err := makeCommit(blockID, h, 0, voteSet, vals, time.Now())
- require.NoError(t, err)
- require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit))
-
- // malleate 3rd signature (2 signatures are enough for 1/3+ trust level)
- vote := voteSet.GetByIndex(2)
- v := vote.ToProto()
- err = vals[2].SignVote(context.Background(), "CentaurusA", v)
- require.NoError(t, err)
- vote.Signature = v.Signature
- commit.Signatures[2] = vote.CommitSig()
-
- err = valSet.VerifyCommitLightTrusting(chainID, commit, tmmath.Fraction{Numerator: 1, Denominator: 3})
- assert.NoError(t, err)
- }
-
- func TestValidatorSet_VerifyCommitLightTrusting(t *testing.T) {
- var (
- blockID = makeBlockIDRandom()
- voteSet, originalValset, vals = randVoteSet(1, 1, tmproto.PrecommitType, 6, 1)
- commit, err = makeCommit(blockID, 1, 1, voteSet, vals, time.Now())
- newValSet, _ = randValidatorPrivValSet(2, 1)
- )
- require.NoError(t, err)
-
- testCases := []struct {
- valSet *ValidatorSet
- err bool
- }{
- // good
- 0: {
- valSet: originalValset,
- err: false,
- },
- // bad - no overlap between validator sets
- 1: {
- valSet: newValSet,
- err: true,
- },
- // good - first two are different but the rest of the same -> >1/3
- 2: {
- valSet: NewValidatorSet(append(newValSet.Validators, originalValset.Validators...)),
- err: false,
- },
- }
-
- for _, tc := range testCases {
- err = tc.valSet.VerifyCommitLightTrusting("test_chain_id", commit,
- tmmath.Fraction{Numerator: 1, Denominator: 3})
- if tc.err {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- }
- }
-
- func TestValidatorSet_VerifyCommitLightTrustingErrorsOnOverflow(t *testing.T) {
- var (
- blockID = makeBlockIDRandom()
- voteSet, valSet, vals = randVoteSet(1, 1, tmproto.PrecommitType, 1, MaxTotalVotingPower)
- commit, err = makeCommit(blockID, 1, 1, voteSet, vals, time.Now())
- )
- require.NoError(t, err)
-
- err = valSet.VerifyCommitLightTrusting("test_chain_id", commit,
- tmmath.Fraction{Numerator: 25, Denominator: 55})
- if assert.Error(t, err) {
- assert.Contains(t, err.Error(), "int64 overflow")
- }
- }
|