evidence: remove phantom validator evidence (#5181)

This commit is contained in:
Callum Waters
2020-07-31 12:23:58 +02:00
committed by GitHub
parent db345066a8
commit 3c21c3546c
11 changed files with 104 additions and 852 deletions

View File

@@ -225,51 +225,21 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence, commit
addr := evidence.Address()
var val *types.Validator
// For PhantomValidatorEvidence, check evidence.Address was not part of the
// validator set at height evidence.Height, but was a validator before OR
// after.
if phve, ok := evidence.(*types.PhantomValidatorEvidence); ok {
// confirm that it hasn't been forged
_, val = valset.GetByAddress(addr)
if val != nil {
return fmt.Errorf("address %X was a validator at height %d", addr, evidence.Height())
}
// check if last height validator was in the validator set is within
// MaxAgeNumBlocks.
if height-phve.LastHeightValidatorWasInSet > evidenceParams.MaxAgeNumBlocks {
return fmt.Errorf("last time validator was in the set at height %d, min: %d",
phve.LastHeightValidatorWasInSet, height-phve.LastHeightValidatorWasInSet)
}
valset, err := LoadValidators(stateDB, phve.LastHeightValidatorWasInSet)
if err != nil {
// TODO: if err is just that we cant find it cuz we pruned, ignore.
// TODO: if its actually bad evidence, punish peer
return err
}
_, val = valset.GetByAddress(addr)
if val == nil {
return fmt.Errorf("phantom validator %X not found", addr)
}
} else {
if ae, ok := evidence.(*types.AmnesiaEvidence); ok {
// check the validator set against the polc to make sure that a majority of valid votes was reached
if !ae.Polc.IsAbsent() {
err = ae.Polc.ValidateVotes(valset, state.ChainID)
if err != nil {
return fmt.Errorf("amnesia evidence contains invalid polc, err: %w", err)
}
if ae, ok := evidence.(*types.AmnesiaEvidence); ok {
// check the validator set against the polc to make sure that a majority of valid votes was reached
if !ae.Polc.IsAbsent() {
err = ae.Polc.ValidateVotes(valset, state.ChainID)
if err != nil {
return fmt.Errorf("amnesia evidence contains invalid polc, err: %w", err)
}
}
}
// For all other types, expect evidence.Address to be a validator at height
// evidence.Height.
_, val = valset.GetByAddress(addr)
if val == nil {
return fmt.Errorf("address %X was not a validator at height %d", addr, evidence.Height())
}
// For all other types, expect evidence.Address to be a validator at height
// evidence.Height.
_, val = valset.GetByAddress(addr)
if val == nil {
return fmt.Errorf("address %X was not a validator at height %d", addr, evidence.Height())
}
if err := evidence.Verify(state.ChainID, val.PubKey); err != nil {

View File

@@ -16,7 +16,6 @@ import (
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/libs/log"
memmock "github.com/tendermint/tendermint/mempool/mock"
protostate "github.com/tendermint/tendermint/proto/tendermint/state"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/state/mocks"
@@ -622,85 +621,6 @@ func TestVerifyEvidenceWithLunaticValidatorEvidence(t *testing.T) {
}
}
func TestVerifyEvidenceWithPhantomValidatorEvidence(t *testing.T) {
state, stateDB, vals := makeState(4, 4)
state.ConsensusParams.Evidence.MaxAgeNumBlocks = 1
addr, val := state.Validators.GetByIndex(0)
vote := makeVote(3, 1, 0, addr, blockID)
v := vote.ToProto()
err := vals[val.Address.String()].SignVote(chainID, v)
vote.Signature = v.Signature
require.NoError(t, err)
ev := &types.PhantomValidatorEvidence{
Vote: vote,
LastHeightValidatorWasInSet: 1,
}
err = ev.ValidateBasic()
require.NoError(t, err)
err = sm.VerifyEvidence(stateDB, state, ev, nil)
if assert.Error(t, err) {
assert.Equal(t, "address 576585A00DD4D58318255611D8AAC60E8E77CB32 was a validator at height 3", err.Error())
}
privVal := types.NewMockPV()
pubKey, _ := privVal.GetPubKey()
vote2 := makeVote(3, 1, 0, pubKey.Address(), blockID)
v2 := vote2.ToProto()
err = privVal.SignVote(chainID, v2)
vote2.Signature = v2.Signature
require.NoError(t, err)
ev = &types.PhantomValidatorEvidence{
Vote: vote2,
LastHeightValidatorWasInSet: 1,
}
err = ev.ValidateBasic()
assert.NoError(t, err)
err = sm.VerifyEvidence(stateDB, state, ev, nil)
if assert.Error(t, err) {
assert.Equal(t, "last time validator was in the set at height 1, min: 2", err.Error())
}
ev = &types.PhantomValidatorEvidence{
Vote: vote2,
LastHeightValidatorWasInSet: 2,
}
err = ev.ValidateBasic()
assert.NoError(t, err)
err = sm.VerifyEvidence(stateDB, state, ev, nil)
errMsg := "phantom validator"
if assert.Error(t, err) {
assert.Equal(t, errMsg, err.Error()[:len(errMsg)])
}
vals2, err := sm.LoadValidators(stateDB, 2)
require.NoError(t, err)
vals2.Validators = append(vals2.Validators, types.NewValidator(pubKey, 1000))
valKey := []byte("validatorsKey:2")
protoVals, err := vals2.ToProto()
require.NoError(t, err)
valInfo := &protostate.ValidatorsInfo{
LastHeightChanged: 2,
ValidatorSet: protoVals,
}
bz, err := valInfo.Marshal()
require.NoError(t, err)
err = stateDB.Set(valKey, bz)
require.NoError(t, err)
ev = &types.PhantomValidatorEvidence{
Vote: vote2,
LastHeightValidatorWasInSet: 2,
}
err = ev.ValidateBasic()
assert.NoError(t, err)
err = sm.VerifyEvidence(stateDB, state, ev, nil)
if !assert.NoError(t, err) {
t.Log(err)
}
}
func makeVote(height int64, round, index int32, addr bytes.HexBytes, blockID types.BlockID) *types.Vote {
return &types.Vote{
Type: tmproto.SignedMsgType(2),