From b2561cd17ff9fdaf00fc76fe42ec4700636c8a2e Mon Sep 17 00:00:00 2001 From: Mostafa Date: Tue, 24 Sep 2024 13:08:01 +0800 Subject: [PATCH] refactor(types): define errors for vote package --- consensus/cp.go | 34 +++++------ consensus/cp_test.go | 44 ++++++------- consensus/errors.go | 6 +- consensus/voteset/binary_voteset.go | 3 +- consensus/voteset/block_voteset.go | 3 +- consensus/voteset/errors.go | 20 ++++++ consensus/voteset/voteset.go | 9 ++- consensus/voteset/voteset_test.go | 25 ++++---- types/vote/cp_vote.go | 9 ++- types/vote/vote.go | 21 ++++--- types/vote/vote_test.go | 95 ++++++++++++++++------------- util/errors/errors.go | 6 -- 12 files changed, 151 insertions(+), 124 deletions(-) create mode 100644 consensus/voteset/errors.go diff --git a/consensus/cp.go b/consensus/cp.go index abb278568..b23256ca9 100644 --- a/consensus/cp.go +++ b/consensus/cp.go @@ -30,7 +30,7 @@ func (*changeProposer) checkCPValue(vte *vote.Vote, allowedValues ...vote.CPValu } } - return invalidJustificationError{ + return InvalidJustificationError{ JustType: vte.CPJust().Type(), Reason: fmt.Sprintf("invalid value: %v", vte.CPValue()), } @@ -39,7 +39,7 @@ func (*changeProposer) checkCPValue(vte *vote.Vote, allowedValues ...vote.CPValu func (cp *changeProposer) checkJustInitZero(just vote.Just, blockHash hash.Hash) error { j, ok := just.(*vote.JustInitNo) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid just data", } @@ -47,7 +47,7 @@ func (cp *changeProposer) checkJustInitZero(just vote.Just, blockHash hash.Hash) err := j.QCert.ValidatePrepare(cp.validators, blockHash) if err != nil { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: j.Type(), Reason: err.Error(), } @@ -59,7 +59,7 @@ func (cp *changeProposer) checkJustInitZero(just vote.Just, blockHash hash.Hash) func (*changeProposer) checkJustInitOne(just vote.Just) error { _, ok := just.(*vote.JustInitYes) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid just data", } @@ -73,7 +73,7 @@ func (cp *changeProposer) checkJustPreVoteHard(just vote.Just, ) error { j, ok := just.(*vote.JustPreVoteHard) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid just data", } @@ -82,7 +82,7 @@ func (cp *changeProposer) checkJustPreVoteHard(just vote.Just, err := j.QCert.ValidateCPPreVote(cp.validators, blockHash, cpRound-1, byte(cpValue)) if err != nil { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: err.Error(), } @@ -96,7 +96,7 @@ func (cp *changeProposer) checkJustPreVoteSoft(just vote.Just, ) error { j, ok := just.(*vote.JustPreVoteSoft) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid just data", } @@ -105,7 +105,7 @@ func (cp *changeProposer) checkJustPreVoteSoft(just vote.Just, err := j.QCert.ValidateCPMainVote(cp.validators, blockHash, cpRound-1, byte(vote.CPValueAbstain)) if err != nil { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: err.Error(), } @@ -119,7 +119,7 @@ func (cp *changeProposer) checkJustMainVoteNoConflict(just vote.Just, ) error { j, ok := just.(*vote.JustMainVoteNoConflict) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid just data", } @@ -128,7 +128,7 @@ func (cp *changeProposer) checkJustMainVoteNoConflict(just vote.Just, err := j.QCert.ValidateCPPreVote(cp.validators, blockHash, cpRound, byte(cpValue)) if err != nil { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: j.Type(), Reason: err.Error(), } @@ -143,7 +143,7 @@ func (cp *changeProposer) checkJustMainVoteConflict(just vote.Just, ) error { j, ok := just.(*vote.JustMainVoteConflict) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid just data", } @@ -176,7 +176,7 @@ func (cp *changeProposer) checkJustMainVoteConflict(just vote.Just, return err } default: - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: fmt.Sprintf("unexpected justification: %s", j.JustNo.Type()), } @@ -211,7 +211,7 @@ func (cp *changeProposer) checkJustPreVote(v *vote.Vote) error { return cp.checkJustInitOne(just) default: - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid pre-vote justification", } @@ -235,7 +235,7 @@ func (cp *changeProposer) checkJustPreVote(v *vote.Vote) error { return cp.checkJustPreVoteHard(just, v.BlockHash(), v.CPRound(), v.CPValue()) default: - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid pre-vote justification", } @@ -264,7 +264,7 @@ func (cp *changeProposer) checkJustMainVote(v *vote.Vote) error { return cp.checkJustMainVoteConflict(just, v.BlockHash(), v.CPRound()) default: - return invalidJustificationError{ + return InvalidJustificationError{ JustType: just.Type(), Reason: "invalid main-vote justification", } @@ -278,7 +278,7 @@ func (cp *changeProposer) checkJustDecide(v *vote.Vote) error { } j, ok := v.CPJust().(*vote.JustDecided) if !ok { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: j.Type(), Reason: "invalid just data", } @@ -287,7 +287,7 @@ func (cp *changeProposer) checkJustDecide(v *vote.Vote) error { err = j.QCert.ValidateCPMainVote(cp.validators, v.BlockHash(), v.CPRound(), byte(v.CPValue())) if err != nil { - return invalidJustificationError{ + return InvalidJustificationError{ JustType: j.Type(), Reason: err.Error(), } diff --git a/consensus/cp_test.go b/consensus/cp_test.go index bebd17998..83953c8ff 100644 --- a/consensus/cp_test.go +++ b/consensus/cp_test.go @@ -142,7 +142,7 @@ func TestInvalidJustInitOne(t *testing.T) { v := vote.NewCPPreVote(hash.UndefHash, h, r, 0, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: no", }) @@ -152,7 +152,7 @@ func TestInvalidJustInitOne(t *testing.T) { v := vote.NewCPPreVote(hash.UndefHash, h, r, 1, vote.CPValueYes, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid pre-vote justification", }) @@ -163,7 +163,7 @@ func TestInvalidJustInitOne(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 0, vote.CPValueYes, invJust, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: invJust.Type(), Reason: "invalid pre-vote justification", }) @@ -184,7 +184,7 @@ func TestInvalidJustInitZero(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 0, vote.CPValueYes, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: yes", }) @@ -194,7 +194,7 @@ func TestInvalidJustInitZero(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 1, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid pre-vote justification", }) @@ -204,7 +204,7 @@ func TestInvalidJustInitZero(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 0, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just.QCert.Committers()), }) @@ -225,7 +225,7 @@ func TestInvalidJustPreVoteHard(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 1, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: abstain", }) @@ -235,7 +235,7 @@ func TestInvalidJustPreVoteHard(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 0, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid pre-vote justification", }) @@ -245,7 +245,7 @@ func TestInvalidJustPreVoteHard(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 1, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just.QCert.Committers()), }) @@ -266,7 +266,7 @@ func TestInvalidJustPreVoteSoft(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 1, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: abstain", }) @@ -276,7 +276,7 @@ func TestInvalidJustPreVoteSoft(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 0, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid pre-vote justification", }) @@ -286,7 +286,7 @@ func TestInvalidJustPreVoteSoft(t *testing.T) { v := vote.NewCPPreVote(td.RandHash(), h, r, 1, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just.QCert.Committers()), }) @@ -307,7 +307,7 @@ func TestInvalidJustMainVoteNoConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 1, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: abstain", }) @@ -317,7 +317,7 @@ func TestInvalidJustMainVoteNoConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 1, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just.QCert.Committers()), }) @@ -341,7 +341,7 @@ func TestInvalidJustMainVoteConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 0, vote.CPValueNo, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: no", }) @@ -357,7 +357,7 @@ func TestInvalidJustMainVoteConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 0, vote.CPValueYes, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: yes", }) @@ -373,7 +373,7 @@ func TestInvalidJustMainVoteConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 0, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: vote.JustTypePreVoteSoft, Reason: "invalid just data", }) @@ -391,7 +391,7 @@ func TestInvalidJustMainVoteConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 1, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "unexpected justification: JustInitNo", }) @@ -408,7 +408,7 @@ func TestInvalidJustMainVoteConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 0, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just0.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just0.QCert.Committers()), }) @@ -427,7 +427,7 @@ func TestInvalidJustMainVoteConflict(t *testing.T) { v := vote.NewCPMainVote(td.RandHash(), h, r, 1, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just0.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just0.QCert.Committers()), }) @@ -448,7 +448,7 @@ func TestInvalidJustDecided(t *testing.T) { v := vote.NewCPDecidedVote(td.RandHash(), h, r, 0, vote.CPValueAbstain, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: "invalid value: abstain", }) @@ -458,7 +458,7 @@ func TestInvalidJustDecided(t *testing.T) { v := vote.NewCPDecidedVote(td.RandHash(), h, r, 0, vote.CPValueYes, just, td.consB.valKey.Address()) err := td.consX.changeProposer.checkJust(v) - assert.ErrorIs(t, err, invalidJustificationError{ + assert.ErrorIs(t, err, InvalidJustificationError{ JustType: just.Type(), Reason: fmt.Sprintf("certificate has an unexpected committers: %v", just.QCert.Committers()), }) diff --git a/consensus/errors.go b/consensus/errors.go index 190fd309b..b9caa8abe 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -6,14 +6,14 @@ import ( "github.com/pactus-project/pactus/types/vote" ) -// invalidJustificationError is returned when the justification for a change-proposer +// InvalidJustificationError is returned when the justification for a change-proposer // vote is invalid. -type invalidJustificationError struct { +type InvalidJustificationError struct { JustType vote.JustType Reason string } -func (e invalidJustificationError) Error() string { +func (e InvalidJustificationError) Error() string { return fmt.Sprintf("invalid justification: %s, reason: %s", e.JustType.String(), e.Reason) } diff --git a/consensus/voteset/binary_voteset.go b/consensus/voteset/binary_voteset.go index c1250b184..4acbce419 100644 --- a/consensus/voteset/binary_voteset.go +++ b/consensus/voteset/binary_voteset.go @@ -4,7 +4,6 @@ import ( "github.com/pactus-project/pactus/crypto" "github.com/pactus-project/pactus/types/validator" "github.com/pactus-project/pactus/types/vote" - "github.com/pactus-project/pactus/util/errors" ) type roundVotes struct { @@ -105,7 +104,7 @@ func (vs *BinaryVoteSet) AddVote(v *vote.Vote) (bool, error) { } // It is a duplicated vote - err = errors.Error(errors.ErrDuplicateVote) + err = ErrDuplicatedVote } else { roundVotes.allVotes[v.Signer()] = v roundVotes.votedPower += power diff --git a/consensus/voteset/block_voteset.go b/consensus/voteset/block_voteset.go index 0cc272156..87229839b 100644 --- a/consensus/voteset/block_voteset.go +++ b/consensus/voteset/block_voteset.go @@ -5,7 +5,6 @@ import ( "github.com/pactus-project/pactus/crypto/hash" "github.com/pactus-project/pactus/types/validator" "github.com/pactus-project/pactus/types/vote" - "github.com/pactus-project/pactus/util/errors" ) type BlockVoteSet struct { @@ -84,7 +83,7 @@ func (vs *BlockVoteSet) AddVote(v *vote.Vote) (bool, error) { } // It is a duplicated vote - err = errors.Error(errors.ErrDuplicateVote) + err = ErrDuplicatedVote } else { vs.allVotes[v.Signer()] = v } diff --git a/consensus/voteset/errors.go b/consensus/voteset/errors.go new file mode 100644 index 000000000..344d11c56 --- /dev/null +++ b/consensus/voteset/errors.go @@ -0,0 +1,20 @@ +package voteset + +import ( + "errors" + "fmt" + + "github.com/pactus-project/pactus/crypto" +) + +// ErrDuplicatedVote is returned when a duplicated vote from a validator is detected. +var ErrDuplicatedVote = errors.New("duplicated vote") + +// IneligibleVoterError is returned when the voter is not a member of the committee. +type IneligibleVoterError struct { + Address crypto.Address +} + +func (e IneligibleVoterError) Error() string { + return fmt.Sprintf("validator %s is not part of the committee", e.Address) +} diff --git a/consensus/voteset/voteset.go b/consensus/voteset/voteset.go index c1135a31b..33a2666a4 100644 --- a/consensus/voteset/voteset.go +++ b/consensus/voteset/voteset.go @@ -4,7 +4,6 @@ import ( "github.com/pactus-project/pactus/crypto" "github.com/pactus-project/pactus/types/validator" "github.com/pactus-project/pactus/types/vote" - "github.com/pactus-project/pactus/util/errors" ) type voteSet struct { @@ -34,13 +33,13 @@ func (vs *voteSet) verifyVote(v *vote.Vote) (int64, error) { signer := v.Signer() val := vs.validators[signer] if val == nil { - return 0, errors.Errorf(errors.ErrInvalidAddress, - "cannot find validator %s in committee", signer) + return 0, IneligibleVoterError{ + Address: signer, + } } if err := v.Verify(val.PublicKey()); err != nil { - return 0, errors.Errorf(errors.ErrInvalidSignature, - "failed to verify vote") + return 0, err } return val.Power(), nil diff --git a/consensus/voteset/voteset_test.go b/consensus/voteset/voteset_test.go index 95f721f87..37d03d056 100644 --- a/consensus/voteset/voteset_test.go +++ b/consensus/voteset/voteset_test.go @@ -9,7 +9,6 @@ import ( "github.com/pactus-project/pactus/types/amount" "github.com/pactus-project/pactus/types/validator" "github.com/pactus-project/pactus/types/vote" - "github.com/pactus-project/pactus/util/errors" "github.com/pactus-project/pactus/util/testsuite" "github.com/stretchr/testify/assert" ) @@ -51,12 +50,12 @@ func TestAddBlockVote(t *testing.T) { ts.HelperSignVote(invKey, v1) added, err := vs.AddVote(v1) - assert.Equal(t, errors.ErrInvalidAddress, errors.Code(err)) // unknown validator + assert.ErrorIs(t, err, IneligibleVoterError{Address: v1.Signer()}) // unknown validator assert.False(t, added) ts.HelperSignVote(invKey, v2) added, err = vs.AddVote(v2) - assert.Equal(t, errors.ErrInvalidSignature, errors.Code(err)) // invalid signature + assert.ErrorIs(t, err, crypto.ErrInvalidSignature) // invalid signature assert.False(t, added) ts.HelperSignVote(valKey, v2) @@ -70,7 +69,7 @@ func TestAddBlockVote(t *testing.T) { ts.HelperSignVote(valKey, v3) added, err = vs.AddVote(v3) - assert.Equal(t, errors.ErrDuplicateVote, errors.Code(err)) + assert.ErrorIs(t, err, ErrDuplicatedVote) assert.True(t, added) } @@ -96,12 +95,12 @@ func TestAddBinaryVote(t *testing.T) { ts.HelperSignVote(invKey, v1) added, err := vs.AddVote(v1) - assert.Equal(t, errors.ErrInvalidAddress, errors.Code(err)) // unknown validator + assert.ErrorIs(t, err, IneligibleVoterError{Address: v1.Signer()}) // unknown validator assert.False(t, added) ts.HelperSignVote(invKey, v2) added, err = vs.AddVote(v2) - assert.Equal(t, errors.ErrInvalidSignature, errors.Code(err)) // invalid signature + assert.ErrorIs(t, err, crypto.ErrInvalidSignature) // invalid signature assert.False(t, added) ts.HelperSignVote(valKey, v2) @@ -115,7 +114,7 @@ func TestAddBinaryVote(t *testing.T) { ts.HelperSignVote(valKey, v3) added, err = vs.AddVote(v3) - assert.Equal(t, errors.ErrDuplicateVote, errors.Code(err)) + assert.ErrorIs(t, err, ErrDuplicatedVote) assert.True(t, added) } @@ -144,11 +143,11 @@ func TestDuplicateBlockVote(t *testing.T) { assert.True(t, added) added, err = vs.AddVote(duplicatedVote1) - assert.Equal(t, errors.ErrDuplicateVote, errors.Code(err)) + assert.ErrorIs(t, err, ErrDuplicatedVote) assert.True(t, added) added, err = vs.AddVote(duplicatedVote2) - assert.Equal(t, errors.ErrDuplicateVote, errors.Code(err)) + assert.ErrorIs(t, err, ErrDuplicatedVote) assert.True(t, added) bv1 := vs.BlockVotes(h1) @@ -185,11 +184,11 @@ func TestDuplicateBinaryVote(t *testing.T) { assert.True(t, added) added, err = vs.AddVote(duplicatedVote1) - assert.Equal(t, errors.ErrDuplicateVote, errors.Code(err)) + assert.ErrorIs(t, err, ErrDuplicatedVote) assert.True(t, added) added, err = vs.AddVote(duplicatedVote2) - assert.Equal(t, errors.ErrDuplicateVote, errors.Code(err)) + assert.ErrorIs(t, err, ErrDuplicatedVote) assert.True(t, added) assert.False(t, vs.HasOneThirdOfTotalPower(0)) @@ -257,7 +256,7 @@ func TestAllBlockVotes(t *testing.T) { ts.HelperSignVote(valKeys[0], v1) ts.HelperSignVote(valKeys[1], v2) ts.HelperSignVote(valKeys[2], v3) - ts.HelperSignVote(valKeys[3], v4) + ts.HelperSignVote(valKeys[0], v4) _, err := vs.AddVote(v1) assert.NoError(t, err) @@ -271,7 +270,7 @@ func TestAllBlockVotes(t *testing.T) { assert.Equal(t, &h1, vs.QuorumHash()) _, err = vs.AddVote(v4) - assert.Error(t, err) // duplicated + assert.ErrorIs(t, err, ErrDuplicatedVote) // duplicated // Check accumulated power assert.Equal(t, &h1, vs.QuorumHash()) diff --git a/types/vote/cp_vote.go b/types/vote/cp_vote.go index 6b2e3a7c4..d89a252b1 100644 --- a/types/vote/cp_vote.go +++ b/types/vote/cp_vote.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/fxamacker/cbor/v2" - "github.com/pactus-project/pactus/util/errors" ) type CPValue int8 @@ -36,12 +35,16 @@ type cpVote struct { func (v *cpVote) BasicCheck() error { if v.Round < 0 { - return errors.Error(errors.ErrInvalidRound) + return BasicCheckError{ + Reason: "invalid CP round", + } } if v.Value < CPValueNo || v.Value > CPValueAbstain { // Invalid values - return errors.Errorf(errors.ErrInvalidVote, "cp value should be 0, 1 or abstain") + return BasicCheckError{ + Reason: "invalid CP value", + } } return v.Just.BasicCheck() diff --git a/types/vote/vote.go b/types/vote/vote.go index 554304200..9fdb6eeac 100644 --- a/types/vote/vote.go +++ b/types/vote/vote.go @@ -8,7 +8,6 @@ import ( "github.com/pactus-project/pactus/crypto/bls" "github.com/pactus-project/pactus/crypto/hash" "github.com/pactus-project/pactus/util" - "github.com/pactus-project/pactus/util/errors" ) // Vote is a struct that represents a consensus vote. @@ -184,10 +183,6 @@ func (v *Vote) Hash() hash.Hash { // Verify checks the signature of the vote with the given public key. func (v *Vote) Verify(pubKey *bls.PublicKey) error { - if v.Signature() == nil { - return errors.Errorf(errors.ErrInvalidVote, "no signature") - } - if v.Signer() != pubKey.ValidatorAddress() { return InvalidSignerError{ Expected: pubKey.ValidatorAddress(), @@ -211,7 +206,9 @@ func (v *Vote) IsCPVote() bool { // BasicCheck performs a basic check on the vote. func (v *Vote) BasicCheck() error { if !v.data.Type.IsValid() { - return errors.Errorf(errors.ErrInvalidVote, "invalid vote type") + return BasicCheckError{ + Reason: "invalid vote type", + } } if v.data.Height <= 0 { return BasicCheckError{ @@ -225,16 +222,22 @@ func (v *Vote) BasicCheck() error { } if v.IsCPVote() { if v.data.CPVote == nil { - return errors.Errorf(errors.ErrInvalidVote, "should have cp data") + return BasicCheckError{ + Reason: "should have CP data", + } } if err := v.data.CPVote.BasicCheck(); err != nil { return err } } else if v.data.CPVote != nil { - return errors.Errorf(errors.ErrInvalidVote, "should not have cp data") + return BasicCheckError{ + Reason: "should not have CP data", + } } if v.Signature() == nil { - return errors.Errorf(errors.ErrInvalidSignature, "no signature") + return BasicCheckError{ + Reason: "no signature", + } } return nil diff --git a/types/vote/vote_test.go b/types/vote/vote_test.go index 132032515..ed05464b3 100644 --- a/types/vote/vote_test.go +++ b/types/vote/vote_test.go @@ -4,10 +4,9 @@ import ( "encoding/hex" "testing" - "github.com/pactus-project/pactus/crypto/bls" + "github.com/pactus-project/pactus/crypto" "github.com/pactus-project/pactus/crypto/hash" "github.com/pactus-project/pactus/types/vote" - "github.com/pactus-project/pactus/util/errors" "github.com/pactus-project/pactus/util/testsuite" "github.com/stretchr/testify/assert" ) @@ -232,19 +231,25 @@ func TestVoteSignature(t *testing.T) { v1 := vote.NewPrepareVote(h1, 101, 5, pb1.ValidatorAddress()) v2 := vote.NewPrepareVote(h1, 101, 5, pb2.ValidatorAddress()) - assert.Error(t, v1.Verify(pb1), "No signature") + assert.Error(t, v1.BasicCheck(), "No signature") - sig1 := pv1.Sign(v1.SignBytes()) - v1.SetSignature(sig1.(*bls.Signature)) - assert.NoError(t, v1.Verify(pb1), "Ok") + sig1 := pv1.SignNative(v1.SignBytes()) + v1.SetSignature(sig1) + err1 := v1.Verify(pb1) + assert.NoError(t, err1, "Ok") - sig2 := pv2.Sign(v2.SignBytes()) - v2.SetSignature(sig2.(*bls.Signature)) - assert.Error(t, v2.Verify(pb1), "invalid public key") + sig2 := pv2.SignNative(v2.SignBytes()) + v2.SetSignature(sig2) + err2 := v2.Verify(pb1) + assert.ErrorIs(t, err2, vote.InvalidSignerError{ + Expected: pb1.ValidatorAddress(), + Got: pb2.ValidatorAddress(), + }) - sig3 := pv1.Sign(v2.SignBytes()) - v2.SetSignature(sig3.(*bls.Signature)) - assert.Error(t, v2.Verify(pb2), "invalid signature") + sig3 := pv1.SignNative(v2.SignBytes()) + v2.SetSignature(sig3) + err3 := v2.Verify(pb2) + assert.ErrorIs(t, err3, crypto.ErrInvalidSignature) } func TestCPPreVote(t *testing.T) { @@ -254,20 +259,22 @@ func TestCPPreVote(t *testing.T) { r := ts.RandRound() just := &vote.JustInitYes{} - t.Run("Invalid round", func(t *testing.T) { + t.Run("Invalid CP round", func(t *testing.T) { + invalidCPRound := int16(-1) v := vote.NewCPPreVote(hash.UndefHash, h, r, - -1, vote.CPValueYes, just, ts.RandAccAddress()) + invalidCPRound, vote.CPValueYes, just, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidRound, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "invalid CP round"}) }) - t.Run("Invalid value", func(t *testing.T) { + t.Run("invalid CP value", func(t *testing.T) { + invalidCPValue := vote.CPValue(3) v := vote.NewCPPreVote(hash.UndefHash, h, r, - 1, 3, just, ts.RandAccAddress()) + 1, invalidCPValue, just, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidVote, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "invalid CP value"}) }) t.Run("Ok", func(t *testing.T) { @@ -290,31 +297,33 @@ func TestCPMainVote(t *testing.T) { r := ts.RandRound() just := &vote.JustInitYes{} - t.Run("Invalid round", func(t *testing.T) { + t.Run("Invalid CP round", func(t *testing.T) { + invalidCPRound := int16(-1) v := vote.NewCPMainVote(hash.UndefHash, h, r, - -1, vote.CPValueNo, just, ts.RandAccAddress()) + invalidCPRound, vote.CPValueNo, just, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidRound, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "invalid CP round"}) }) t.Run("No CP data", func(t *testing.T) { data, _ := hex.DecodeString("A701040218320301045820BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "055501AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA06f607f6") v := new(vote.Vote) - err := v.UnmarshalCBOR(data) - assert.NoError(t, err) + _ = v.UnmarshalCBOR(data) v.SetSignature(ts.RandBLSSignature()) - assert.Error(t, v.BasicCheck()) + err := v.BasicCheck() + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "should have CP data"}) }) - t.Run("Invalid value", func(t *testing.T) { + t.Run("Invalid CP value", func(t *testing.T) { + invalidCPValue := vote.CPValue(3) v := vote.NewCPMainVote(hash.UndefHash, h, r, - 1, 3, just, ts.RandAccAddress()) + 1, invalidCPValue, just, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidVote, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "invalid CP value"}) }) t.Run("Ok", func(t *testing.T) { @@ -338,30 +347,32 @@ func TestCPDecided(t *testing.T) { just := &vote.JustInitYes{} t.Run("Invalid round", func(t *testing.T) { + invalidCPRound := int16(-1) v := vote.NewCPDecidedVote(hash.UndefHash, h, r, - -1, vote.CPValueNo, just, ts.RandAccAddress()) + invalidCPRound, vote.CPValueNo, just, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidRound, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "invalid CP round"}) }) t.Run("No CP data", func(t *testing.T) { data, _ := hex.DecodeString("A701050218320301045820BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "055501AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA06f607f6") v := new(vote.Vote) - err := v.UnmarshalCBOR(data) - assert.NoError(t, err) + _ = v.UnmarshalCBOR(data) v.SetSignature(ts.RandBLSSignature()) - assert.Error(t, v.BasicCheck()) + err := v.BasicCheck() + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "should have CP data"}) }) - t.Run("Invalid value", func(t *testing.T) { + t.Run("Invalid CP value", func(t *testing.T) { + invalidCPValue := vote.CPValue(3) v := vote.NewCPDecidedVote(hash.UndefHash, h, r, - 1, 3, just, ts.RandAccAddress()) + 1, invalidCPValue, just, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidVote, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "invalid CP value"}) }) t.Run("Ok", func(t *testing.T) { @@ -380,7 +391,7 @@ func TestCPDecided(t *testing.T) { func TestBasicCheck(t *testing.T) { ts := testsuite.NewTestSuite(t) - t.Run("Invalid type", func(t *testing.T) { + t.Run("Should have CP data", func(t *testing.T) { data, _ := hex.DecodeString("A701050218320301045820BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "055501AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA06f607f6") v := new(vote.Vote) @@ -388,7 +399,7 @@ func TestBasicCheck(t *testing.T) { assert.NoError(t, err) err = v.BasicCheck() - assert.Equal(t, errors.ErrInvalidVote, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "should have CP data"}) }) t.Run("Invalid height", func(t *testing.T) { @@ -409,18 +420,18 @@ func TestBasicCheck(t *testing.T) { v := vote.NewPrepareVote(ts.RandHash(), 100, 0, ts.RandAccAddress()) err := v.BasicCheck() - assert.Equal(t, errors.ErrInvalidSignature, errors.Code(err)) + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "no signature"}) }) - t.Run("Has CP data", func(t *testing.T) { + t.Run("Should not have CP data", func(t *testing.T) { data, _ := hex.DecodeString("A701020218320301045820BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "055501AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA06A40100020103020441A007f6") v := new(vote.Vote) - err := v.UnmarshalCBOR(data) - assert.NoError(t, err) + _ = v.UnmarshalCBOR(data) v.SetSignature(ts.RandBLSSignature()) - assert.Error(t, v.BasicCheck()) + err := v.BasicCheck() + assert.ErrorIs(t, err, vote.BasicCheckError{Reason: "should not have CP data"}) }) t.Run("Ok", func(t *testing.T) { diff --git a/util/errors/errors.go b/util/errors/errors.go index f67d198e2..5ba9a28fb 100644 --- a/util/errors/errors.go +++ b/util/errors/errors.go @@ -7,15 +7,12 @@ import ( const ( ErrNone = iota ErrGeneric - ErrInvalidAddress ErrInvalidPublicKey ErrInvalidPrivateKey ErrInvalidSignature ErrInvalidHeight ErrInvalidRound - ErrInvalidVote ErrInvalidMessage - ErrDuplicateVote ErrCount ) @@ -23,15 +20,12 @@ const ( var messages = map[int]string{ ErrNone: "no error", ErrGeneric: "generic error", - ErrInvalidAddress: "invalid address", ErrInvalidPublicKey: "invalid public key", ErrInvalidPrivateKey: "invalid private key", ErrInvalidSignature: "invalid signature", ErrInvalidHeight: "invalid height", ErrInvalidRound: "invalid round", - ErrInvalidVote: "invalid vote", ErrInvalidMessage: "invalid message", - ErrDuplicateVote: "duplicate vote", } type withCodeError struct {