mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-05 13:05:09 +00:00
evidence: remove phantom validator evidence (#5181)
This commit is contained in:
@@ -80,7 +80,7 @@ type Evidence interface {
|
||||
|
||||
type CompositeEvidence interface {
|
||||
VerifyComposite(committedHeader *Header, valSet *ValidatorSet) error
|
||||
Split(committedHeader *Header, valSet *ValidatorSet, valToLastHeight map[string]int64) []Evidence
|
||||
Split(committedHeader *Header, valSet *ValidatorSet) []Evidence
|
||||
}
|
||||
|
||||
func EvidenceToProto(evidence Evidence) (*tmproto.Evidence, error) {
|
||||
@@ -119,17 +119,6 @@ func EvidenceToProto(evidence Evidence) (*tmproto.Evidence, error) {
|
||||
|
||||
return tp, nil
|
||||
|
||||
case *PhantomValidatorEvidence:
|
||||
pbevi := evi.ToProto()
|
||||
|
||||
tp := &tmproto.Evidence{
|
||||
Sum: &tmproto.Evidence_PhantomValidatorEvidence{
|
||||
PhantomValidatorEvidence: pbevi,
|
||||
},
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
|
||||
case *PotentialAmnesiaEvidence:
|
||||
pbevi := evi.ToProto()
|
||||
|
||||
@@ -172,8 +161,6 @@ func EvidenceFromProto(evidence *tmproto.Evidence) (Evidence, error) {
|
||||
return PotentialAmnesiaEvidenceFromProto(evi.PotentialAmnesiaEvidence)
|
||||
case *tmproto.Evidence_AmnesiaEvidence:
|
||||
return AmnesiaEvidenceFromProto(evi.AmnesiaEvidence)
|
||||
case *tmproto.Evidence_PhantomValidatorEvidence:
|
||||
return PhantomValidatorEvidenceFromProto(evi.PhantomValidatorEvidence)
|
||||
default:
|
||||
return nil, errors.New("evidence is not recognized")
|
||||
}
|
||||
@@ -182,7 +169,6 @@ func EvidenceFromProto(evidence *tmproto.Evidence) (Evidence, error) {
|
||||
func init() {
|
||||
tmjson.RegisterType(&DuplicateVoteEvidence{}, "tendermint/DuplicateVoteEvidence")
|
||||
tmjson.RegisterType(&ConflictingHeadersEvidence{}, "tendermint/ConflictingHeadersEvidence")
|
||||
tmjson.RegisterType(&PhantomValidatorEvidence{}, "tendermint/PhantomValidatorEvidence")
|
||||
tmjson.RegisterType(&LunaticValidatorEvidence{}, "tendermint/LunaticValidatorEvidence")
|
||||
tmjson.RegisterType(&PotentialAmnesiaEvidence{}, "tendermint/PotentialAmnesiaEvidence")
|
||||
tmjson.RegisterType(&AmnesiaEvidence{}, "tendermint/AmnesiaEvidence")
|
||||
@@ -417,17 +403,13 @@ func NewConflictingHeadersEvidence(h1, h2 *SignedHeader) *ConflictingHeadersEvid
|
||||
return &ConflictingHeadersEvidence{H1: h1, H2: h2}
|
||||
}
|
||||
|
||||
// Split breaks up evidence into smaller chunks (one per validator except for
|
||||
// PotentialAmnesiaEvidence): PhantomValidatorEvidence,
|
||||
// Split breaks up evidence into smaller chunks of evidence:
|
||||
// LunaticValidatorEvidence, DuplicateVoteEvidence and
|
||||
// PotentialAmnesiaEvidence.
|
||||
//
|
||||
// committedHeader - header at height H1.Height == H2.Height
|
||||
// valSet - validator set at height H1.Height == H2.Height
|
||||
// valToLastHeight - map between active validators and respective last heights
|
||||
func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *ValidatorSet,
|
||||
valToLastHeight map[string]int64) []Evidence {
|
||||
|
||||
func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *ValidatorSet) []Evidence {
|
||||
evList := make([]Evidence, 0)
|
||||
|
||||
var alternativeHeader *SignedHeader
|
||||
@@ -437,28 +419,6 @@ func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *Val
|
||||
alternativeHeader = ev.H1
|
||||
}
|
||||
|
||||
// If there are signers(alternativeHeader) that are not part of
|
||||
// validators(committedHeader), they misbehaved as they are signing protocol
|
||||
// messages in heights they are not validators => immediately slashable
|
||||
// (#F4).
|
||||
for i, sig := range alternativeHeader.Commit.Signatures {
|
||||
if sig.Absent() {
|
||||
continue
|
||||
}
|
||||
|
||||
lastHeightValidatorWasInSet, ok := valToLastHeight[string(sig.ValidatorAddress)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if !valSet.HasAddress(sig.ValidatorAddress) {
|
||||
evList = append(evList, &PhantomValidatorEvidence{
|
||||
Vote: alternativeHeader.Commit.GetVote(int32(i)),
|
||||
LastHeightValidatorWasInSet: lastHeightValidatorWasInSet,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// If ValidatorsHash, NextValidatorsHash, ConsensusHash, AppHash, and
|
||||
// LastResultsHash in alternativeHeader are different (incorrect application
|
||||
// state transition), then it is a lunatic misbehavior => immediately
|
||||
@@ -707,133 +667,6 @@ func ConflictingHeadersEvidenceFromProto(pb *tmproto.ConflictingHeadersEvidence)
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
type PhantomValidatorEvidence struct {
|
||||
Vote *Vote `json:"vote"`
|
||||
LastHeightValidatorWasInSet int64 `json:"last_height_validator_was_in_set"`
|
||||
}
|
||||
|
||||
var _ Evidence = &PhantomValidatorEvidence{}
|
||||
|
||||
// NewPhantomValidatorEvidence creates a new instance of the respective evidence
|
||||
func NewPhantomValidatorEvidence(vote *Vote, lastHeightValidatorWasInSet int64) *PhantomValidatorEvidence {
|
||||
return &PhantomValidatorEvidence{
|
||||
Vote: vote,
|
||||
LastHeightValidatorWasInSet: lastHeightValidatorWasInSet,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Height() int64 {
|
||||
return e.Vote.Height
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Time() time.Time {
|
||||
return e.Vote.Timestamp
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Address() []byte {
|
||||
return e.Vote.ValidatorAddress
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Hash() []byte {
|
||||
pbe := e.ToProto()
|
||||
|
||||
bz, err := pbe.Marshal()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmhash.Sum(bz)
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Bytes() []byte {
|
||||
pbe := e.ToProto()
|
||||
|
||||
bz, err := pbe.Marshal()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return bz
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
|
||||
v := e.Vote.ToProto()
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, v), e.Vote.Signature) {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Equal(ev Evidence) bool {
|
||||
if e2, ok := ev.(*PhantomValidatorEvidence); ok {
|
||||
return e.Vote.Height == e2.Vote.Height &&
|
||||
bytes.Equal(e.Vote.ValidatorAddress, e2.Vote.ValidatorAddress)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) ValidateBasic() error {
|
||||
if e == nil {
|
||||
return errors.New("empty phantom validator evidence")
|
||||
}
|
||||
|
||||
if e.Vote == nil {
|
||||
return errors.New("empty vote")
|
||||
}
|
||||
|
||||
if err := e.Vote.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid vote: %w", err)
|
||||
}
|
||||
|
||||
if !e.Vote.BlockID.IsComplete() {
|
||||
return errors.New("expected vote for block")
|
||||
}
|
||||
|
||||
if e.LastHeightValidatorWasInSet <= 0 {
|
||||
return errors.New("negative or zero LastHeightValidatorWasInSet")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) String() string {
|
||||
return fmt.Sprintf("PhantomValidatorEvidence{%X voted at height %d}",
|
||||
e.Vote.ValidatorAddress, e.Vote.Height)
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) ToProto() *tmproto.PhantomValidatorEvidence {
|
||||
vpb := e.Vote.ToProto()
|
||||
|
||||
tp := &tmproto.PhantomValidatorEvidence{
|
||||
Vote: vpb,
|
||||
LastHeightValidatorWasInSet: e.LastHeightValidatorWasInSet,
|
||||
}
|
||||
|
||||
return tp
|
||||
}
|
||||
|
||||
func PhantomValidatorEvidenceFromProto(pb *tmproto.PhantomValidatorEvidence) (*PhantomValidatorEvidence, error) {
|
||||
if pb == nil {
|
||||
return nil, errors.New("nil PhantomValidatorEvidence")
|
||||
}
|
||||
|
||||
vpb, err := VoteFromProto(pb.Vote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tp := &PhantomValidatorEvidence{
|
||||
Vote: vpb,
|
||||
LastHeightValidatorWasInSet: pb.LastHeightValidatorWasInSet,
|
||||
}
|
||||
|
||||
return tp, tp.ValidateBasic()
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
type LunaticValidatorEvidence struct {
|
||||
Header *Header `json:"header"`
|
||||
Vote *Vote `json:"vote"`
|
||||
|
||||
@@ -118,13 +118,6 @@ func TestMaxEvidenceBytes(t *testing.T) {
|
||||
// InvalidHeaderField: "",
|
||||
// }
|
||||
|
||||
// evp := &PhantomValidatorEvidence{
|
||||
// Header: makeHeaderRandom(),
|
||||
// Vote: makeVote(t, val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, math.MaxInt64, blockID2),
|
||||
|
||||
// LastHeightValidatorWasInSet: math.MaxInt64,
|
||||
// }
|
||||
|
||||
// signedHeader := SignedHeader{Header: makeHeaderRandom(), Commit: randCommit(time.Now())}
|
||||
// evc := &ConflictingHeadersEvidence{
|
||||
// H1: &signedHeader,
|
||||
@@ -137,7 +130,6 @@ func TestMaxEvidenceBytes(t *testing.T) {
|
||||
}{
|
||||
{"DuplicateVote", ev},
|
||||
// {"LunaticValidatorEvidence", evl},
|
||||
// {"PhantomValidatorEvidence", evp},
|
||||
// {"ConflictingHeadersEvidence", evc},
|
||||
}
|
||||
|
||||
@@ -270,33 +262,6 @@ func TestLunaticValidatorEvidence(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestPhantomValidatorEvidence(t *testing.T) {
|
||||
var (
|
||||
blockID = makeBlockIDRandom()
|
||||
header = makeHeaderRandom()
|
||||
val = NewMockPV()
|
||||
vote = makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, blockID, defaultVoteTime)
|
||||
)
|
||||
|
||||
ev := NewPhantomValidatorEvidence(vote, header.Height-1)
|
||||
|
||||
assert.Equal(t, header.Height, ev.Height())
|
||||
assert.Equal(t, defaultVoteTime, ev.Time())
|
||||
assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
|
||||
assert.NotEmpty(t, ev.Hash())
|
||||
assert.NotEmpty(t, ev.Bytes())
|
||||
pubKey, err := val.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, ev.Verify(header.ChainID, pubKey))
|
||||
assert.Error(t, ev.Verify("other", pubKey))
|
||||
privKey2 := ed25519.GenPrivKey()
|
||||
pubKey2 := privKey2.PubKey()
|
||||
assert.Error(t, ev.Verify("other", pubKey2))
|
||||
assert.True(t, ev.Equal(ev))
|
||||
assert.NoError(t, ev.ValidateBasic())
|
||||
assert.NotEmpty(t, ev.String())
|
||||
}
|
||||
|
||||
func TestConflictingHeadersEvidence(t *testing.T) {
|
||||
const (
|
||||
chainID = "TestConflictingHeadersEvidence"
|
||||
@@ -739,11 +704,6 @@ func TestEvidenceProto(t *testing.T) {
|
||||
{"PotentialAmnesiaEvidence nil VoteB", &PotentialAmnesiaEvidence{VoteA: v, VoteB: nil}, false, true},
|
||||
{"PotentialAmnesiaEvidence nil VoteA", &PotentialAmnesiaEvidence{VoteA: nil, VoteB: v2}, false, true},
|
||||
{"PotentialAmnesiaEvidence success", &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v}, false, false},
|
||||
{"PhantomValidatorEvidence empty fail", &PhantomValidatorEvidence{}, false, true},
|
||||
{"PhantomValidatorEvidence nil LastHeightValidatorWasInSet", &PhantomValidatorEvidence{Vote: v}, false, true},
|
||||
{"PhantomValidatorEvidence nil Vote", &PhantomValidatorEvidence{LastHeightValidatorWasInSet: 2}, false, true},
|
||||
{"PhantomValidatorEvidence success", &PhantomValidatorEvidence{Vote: v2, LastHeightValidatorWasInSet: 2},
|
||||
false, false},
|
||||
{"AmnesiaEvidence nil ProofOfLockChange", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{},
|
||||
Polc: NewEmptyPOLC()}, false, true},
|
||||
{"AmnesiaEvidence nil Polc",
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
|
||||
const (
|
||||
ABCIEvidenceTypeDuplicateVote = "duplicate/vote"
|
||||
ABCIEvidenceTypePhantom = "phantom"
|
||||
ABCIEvidenceTypeLunatic = "lunatic"
|
||||
ABCIEvidenceTypeAmnesia = "amnesia"
|
||||
)
|
||||
@@ -132,8 +131,6 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.
|
||||
switch ev.(type) {
|
||||
case *DuplicateVoteEvidence:
|
||||
evType = ABCIEvidenceTypeDuplicateVote
|
||||
case *PhantomValidatorEvidence:
|
||||
evType = ABCIEvidenceTypePhantom
|
||||
case *LunaticValidatorEvidence:
|
||||
evType = ABCIEvidenceTypeLunatic
|
||||
case *AmnesiaEvidence:
|
||||
|
||||
Reference in New Issue
Block a user