mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
update Evidence type - requires pubkey and valset to verify and convert to abci.Evidence
This commit is contained in:
parent
e5bca1df6f
commit
3d2c4fd309
@ -367,7 +367,7 @@ func (h *Handshaker) replayBlocks(state sm.State, proxyApp proxy.AppConns, appBl
|
||||
for i := appBlockHeight + 1; i <= finalBlock; i++ {
|
||||
h.logger.Info("Applying block", "height", i)
|
||||
block := h.store.LoadBlock(i)
|
||||
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators)
|
||||
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators, h.stateDB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
|
||||
return state, ErrInvalidBlock(err)
|
||||
}
|
||||
|
||||
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, s.LastValidators)
|
||||
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, s.LastValidators, blockExec.db)
|
||||
if err != nil {
|
||||
return state, ErrProxyAppConn(err)
|
||||
}
|
||||
@ -158,7 +158,7 @@ func (blockExec *BlockExecutor) Commit(block *types.Block) ([]byte, error) {
|
||||
// Executes block's transactions on proxyAppConn.
|
||||
// Returns a list of transaction results and updates to the validator set
|
||||
func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
||||
block *types.Block, valSet *types.ValidatorSet) (*ABCIResponses, error) {
|
||||
block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) (*ABCIResponses, error) {
|
||||
var validTxs, invalidTxs = 0, 0
|
||||
|
||||
txIndex := 0
|
||||
@ -184,42 +184,14 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
||||
}
|
||||
proxyAppConn.SetResponseCallback(proxyCb)
|
||||
|
||||
// determine which validators did not sign last block.
|
||||
// only applies after first block
|
||||
if block.Height > 1 {
|
||||
precommitLen := len(block.LastCommit.Precommits)
|
||||
valSetLen := len(valSet.Validators)
|
||||
if precommitLen != valSetLen {
|
||||
// sanity check
|
||||
panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
|
||||
precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, valSet.Validators))
|
||||
}
|
||||
}
|
||||
|
||||
signVals := make([]abci.SigningValidator, len(valSet.Validators))
|
||||
for i, val := range valSet.Validators {
|
||||
var vote *types.Vote
|
||||
if i < len(block.LastCommit.Precommits) {
|
||||
vote = block.LastCommit.Precommits[i]
|
||||
}
|
||||
val := abci.SigningValidator{
|
||||
Validator: types.TM2PB.Validator(val),
|
||||
SignedLastBlock: vote != nil,
|
||||
}
|
||||
signVals[i] = val
|
||||
}
|
||||
|
||||
byzantineVals := make([]abci.Evidence, len(block.Evidence.Evidence))
|
||||
for i, ev := range block.Evidence.Evidence {
|
||||
byzantineVals[i] = types.TM2PB.Evidence(ev)
|
||||
}
|
||||
signVals, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
|
||||
|
||||
// Begin block
|
||||
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
||||
Hash: block.Hash(),
|
||||
Header: types.TM2PB.Header(block.Header),
|
||||
Validators: signVals,
|
||||
ByzantineValidators: byzantineVals,
|
||||
ByzantineValidators: byzVals,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
|
||||
@ -251,6 +223,50 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
||||
return abciResponses, nil
|
||||
}
|
||||
|
||||
func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]abci.SigningValidator, []abci.Evidence) {
|
||||
|
||||
// Sanity check that commit length matches validator set size -
|
||||
// only applies after first block
|
||||
if block.Height > 1 {
|
||||
precommitLen := len(block.LastCommit.Precommits)
|
||||
valSetLen := len(lastValSet.Validators)
|
||||
if precommitLen != valSetLen {
|
||||
// sanity check
|
||||
panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
|
||||
precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, lastValSet.Validators))
|
||||
}
|
||||
}
|
||||
|
||||
// determine which validators did not sign last block.
|
||||
signVals := make([]abci.SigningValidator, len(lastValSet.Validators))
|
||||
for i, val := range lastValSet.Validators {
|
||||
var vote *types.Vote
|
||||
if i < len(block.LastCommit.Precommits) {
|
||||
vote = block.LastCommit.Precommits[i]
|
||||
}
|
||||
val := abci.SigningValidator{
|
||||
Validator: types.TM2PB.Validator(val),
|
||||
SignedLastBlock: vote != nil,
|
||||
}
|
||||
signVals[i] = val
|
||||
}
|
||||
|
||||
byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
|
||||
for i, ev := range block.Evidence.Evidence {
|
||||
// We need the validator set. We already did this in validateBlock.
|
||||
// TODO: Should we instead cache the valset in the evidence itself and add
|
||||
// `SetValidatorSet()` and `ToABCI` methods ?
|
||||
valset, err := LoadValidators(stateDB, ev.Height())
|
||||
if err != nil {
|
||||
panic(err) // shoudn't happen
|
||||
}
|
||||
byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
|
||||
}
|
||||
|
||||
return signVals, byzVals
|
||||
|
||||
}
|
||||
|
||||
// If more or equal than 1/3 of total voting power changed in one block, then
|
||||
// a light client could never prove the transition externally. See
|
||||
// ./lite/doc.go for details on how a light client tracks validators.
|
||||
@ -371,8 +387,8 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty
|
||||
// ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
|
||||
// It returns the application root hash (result of abci.Commit).
|
||||
func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block,
|
||||
logger log.Logger, valSet *types.ValidatorSet) ([]byte, error) {
|
||||
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, valSet)
|
||||
logger log.Logger, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]byte, error) {
|
||||
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, lastValSet, stateDB)
|
||||
if err != nil {
|
||||
logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
|
||||
return nil, err
|
||||
|
@ -32,7 +32,7 @@ func TestApplyBlock(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
defer proxyApp.Stop()
|
||||
|
||||
state, stateDB := state(1), dbm.NewMemDB()
|
||||
state, stateDB := state(1, 1)
|
||||
|
||||
blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
|
||||
MockMempool{}, MockEvidencePool{})
|
||||
@ -55,7 +55,7 @@ func TestBeginBlockValidators(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
defer proxyApp.Stop()
|
||||
|
||||
state := state(2)
|
||||
state, stateDB := state(2, 2)
|
||||
|
||||
prevHash := state.LastBlockID.Hash
|
||||
prevParts := types.PartSetHeader{}
|
||||
@ -78,8 +78,9 @@ func TestBeginBlockValidators(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits}
|
||||
|
||||
// block for height 2
|
||||
block, _ := state.MakeBlock(2, makeTxs(2), lastCommit)
|
||||
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators)
|
||||
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
|
||||
require.Nil(t, err, tc.desc)
|
||||
|
||||
// -> app receives a list of validators with a bool indicating if they signed
|
||||
@ -106,30 +107,31 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
defer proxyApp.Stop()
|
||||
|
||||
state := state(2)
|
||||
state, stateDB := state(2, 12)
|
||||
|
||||
prevHash := state.LastBlockID.Hash
|
||||
prevParts := types.PartSetHeader{}
|
||||
prevBlockID := types.BlockID{prevHash, prevParts}
|
||||
|
||||
height1, idx1, val1 := int64(8), 0, []byte("val1")
|
||||
height2, idx2, val2 := int64(3), 1, []byte("val2")
|
||||
height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address
|
||||
height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address
|
||||
ev1 := types.NewMockGoodEvidence(height1, idx1, val1)
|
||||
ev2 := types.NewMockGoodEvidence(height2, idx2, val2)
|
||||
|
||||
now := time.Now()
|
||||
valSet := state.Validators
|
||||
testCases := []struct {
|
||||
desc string
|
||||
evidence []types.Evidence
|
||||
expectedByzantineValidators []abci.Evidence
|
||||
}{
|
||||
{"none byzantine", []types.Evidence{}, []abci.Evidence{}},
|
||||
{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1)}},
|
||||
{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}},
|
||||
{"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{
|
||||
types.TM2PB.Evidence(ev1),
|
||||
types.TM2PB.Evidence(ev2)}},
|
||||
types.TM2PB.Evidence(ev1, valSet, now),
|
||||
types.TM2PB.Evidence(ev2, valSet, now)}},
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
|
||||
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
||||
votes := []*types.Vote{vote0, vote1}
|
||||
@ -137,8 +139,9 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
|
||||
block, _ := state.MakeBlock(10, makeTxs(2), lastCommit)
|
||||
block.Time = now
|
||||
block.Evidence.Evidence = tc.evidence
|
||||
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators)
|
||||
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
|
||||
require.Nil(t, err, tc.desc)
|
||||
|
||||
// -> app must receive an index of the byzantine validator
|
||||
@ -156,7 +159,7 @@ func makeTxs(height int64) (txs []types.Tx) {
|
||||
return txs
|
||||
}
|
||||
|
||||
func state(nVals int) State {
|
||||
func state(nVals, height int) (State, dbm.DB) {
|
||||
vals := make([]types.GenesisValidator, nVals)
|
||||
for i := 0; i < nVals; i++ {
|
||||
secret := []byte(fmt.Sprintf("test%d", i))
|
||||
@ -170,7 +173,16 @@ func state(nVals int) State {
|
||||
Validators: vals,
|
||||
AppHash: nil,
|
||||
})
|
||||
return s
|
||||
|
||||
// save validators to db for 2 heights
|
||||
stateDB := dbm.NewMemDB()
|
||||
SaveState(stateDB, s)
|
||||
|
||||
for i := 1; i < height; i++ {
|
||||
s.LastBlockHeight += 1
|
||||
SaveState(stateDB, s)
|
||||
}
|
||||
return s, stateDB
|
||||
}
|
||||
|
||||
func makeBlock(state State, height int64) *types.Block {
|
||||
|
@ -173,11 +173,12 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) {
|
||||
}
|
||||
|
||||
if valInfo.ValidatorSet == nil {
|
||||
valInfo = loadValidatorsInfo(db, valInfo.LastHeightChanged)
|
||||
if valInfo == nil {
|
||||
valInfo2 := loadValidatorsInfo(db, valInfo.LastHeightChanged)
|
||||
if valInfo2 == nil {
|
||||
cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as
|
||||
last changed from height %d`, valInfo.LastHeightChanged, height))
|
||||
}
|
||||
valInfo = valInfo2
|
||||
}
|
||||
|
||||
return valInfo.ValidatorSet, nil
|
||||
|
@ -73,6 +73,9 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Each check requires loading an old validator set.
|
||||
// We should cap the amount of evidence per block
|
||||
// to prevent potential proposer DoS.
|
||||
for _, ev := range block.Evidence.Evidence {
|
||||
if err := VerifyEvidence(stateDB, state, ev); err != nil {
|
||||
return types.NewEvidenceInvalidErr(ev, err)
|
||||
@ -82,11 +85,11 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// XXX: What's cheaper (ie. what should be checked first):
|
||||
// evidence internal validity (ie. sig checks) or validator existed (fetch historical val set from db)
|
||||
|
||||
// VerifyEvidence verifies the evidence fully by checking it is internally
|
||||
// consistent and sufficiently recent.
|
||||
// VerifyEvidence verifies the evidence fully by checking:
|
||||
// - it is sufficiently recent (MaxAge)
|
||||
// - it is from a key who was a validator at the given height
|
||||
// - it is internally consistent
|
||||
// - it was properly signed by the alleged equivocator
|
||||
func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error {
|
||||
height := state.LastBlockHeight
|
||||
|
||||
@ -97,10 +100,6 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error
|
||||
evidence.Height(), height-maxAge)
|
||||
}
|
||||
|
||||
if err := evidence.Verify(state.ChainID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valset, err := LoadValidators(stateDB, evidence.Height())
|
||||
if err != nil {
|
||||
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
||||
@ -108,14 +107,18 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error
|
||||
return err
|
||||
}
|
||||
|
||||
// The address must have been an active validator at the height
|
||||
// The address must have been an active validator at the height.
|
||||
// NOTE: we will ignore evidence from H if the key was not a validator
|
||||
// at H, even if it is a validator at some nearby H'
|
||||
ev := evidence
|
||||
height, addr, idx := ev.Height(), ev.Address(), ev.Index()
|
||||
valIdx, val := valset.GetByAddress(addr)
|
||||
height, addr := ev.Height(), ev.Address()
|
||||
_, val := valset.GetByAddress(addr)
|
||||
if val == nil {
|
||||
return fmt.Errorf("Address %X was not a validator at height %d", addr, height)
|
||||
} else if idx != valIdx {
|
||||
return fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx)
|
||||
}
|
||||
|
||||
if err := evidence.Verify(s.ChainID, val.PubKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestValidateBlock(t *testing.T) {
|
||||
state := state(1)
|
||||
state, _ := state(1, 1)
|
||||
|
||||
blockExec := NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nil, nil, nil)
|
||||
|
||||
|
@ -28,12 +28,11 @@ func (err *ErrEvidenceInvalid) Error() string {
|
||||
|
||||
// Evidence represents any provable malicious activity by a validator
|
||||
type Evidence interface {
|
||||
Height() int64 // height of the equivocation
|
||||
Address() []byte // address of the equivocating validator
|
||||
Index() int // index of the validator in the validator set
|
||||
Hash() []byte // hash of the evidence
|
||||
Verify(chainID string) error // verify the evidence
|
||||
Equal(Evidence) bool // check equality of evidence
|
||||
Height() int64 // height of the equivocation
|
||||
Address() []byte // address of the equivocating validator
|
||||
Hash() []byte // hash of the evidence
|
||||
Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence
|
||||
Equal(Evidence) bool // check equality of evidence
|
||||
|
||||
String() string
|
||||
}
|
||||
@ -68,11 +67,6 @@ func (dve *DuplicateVoteEvidence) Address() []byte {
|
||||
return dve.PubKey.Address()
|
||||
}
|
||||
|
||||
// Index returns the index of the validator.
|
||||
func (dve *DuplicateVoteEvidence) Index() int {
|
||||
return dve.VoteA.ValidatorIndex
|
||||
}
|
||||
|
||||
// Hash returns the hash of the evidence.
|
||||
func (dve *DuplicateVoteEvidence) Hash() []byte {
|
||||
return aminoHasher(dve).Hash()
|
||||
@ -80,7 +74,7 @@ func (dve *DuplicateVoteEvidence) Hash() []byte {
|
||||
|
||||
// Verify returns an error if the two votes aren't conflicting.
|
||||
// To be conflicting, they must be from the same validator, for the same H/R/S, but for different blocks.
|
||||
func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
|
||||
func (dve *DuplicateVoteEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
// H/R/S must be the same
|
||||
if dve.VoteA.Height != dve.VoteB.Height ||
|
||||
dve.VoteA.Round != dve.VoteB.Round ||
|
||||
@ -92,7 +86,8 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
|
||||
if !bytes.Equal(dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) {
|
||||
return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress)
|
||||
}
|
||||
// XXX: Should we enforce index is the same ?
|
||||
|
||||
// Index must be the same
|
||||
if dve.VoteA.ValidatorIndex != dve.VoteB.ValidatorIndex {
|
||||
return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.ValidatorIndex, dve.VoteB.ValidatorIndex)
|
||||
}
|
||||
@ -102,11 +97,18 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
|
||||
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID)
|
||||
}
|
||||
|
||||
// pubkey must match address (this should already be true, sanity check)
|
||||
addr := dve.VoteA.ValidatorAddress
|
||||
if !bytes.Equal(pubKey.Address(), addr) {
|
||||
return fmt.Errorf("DuplicateVoteEvidence FAILED SANITY CHECK - address (%X) doesn't match pubkey (%v - %X)",
|
||||
addr, pubKey, pubKey.Address())
|
||||
}
|
||||
|
||||
// Signatures must be valid
|
||||
if !dve.PubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
|
||||
if !pubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
|
||||
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature)
|
||||
}
|
||||
if !dve.PubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
|
||||
if !pubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
|
||||
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature)
|
||||
}
|
||||
|
||||
@ -131,29 +133,26 @@ func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool {
|
||||
type MockGoodEvidence struct {
|
||||
Height_ int64
|
||||
Address_ []byte
|
||||
Index_ int
|
||||
}
|
||||
|
||||
// UNSTABLE
|
||||
func NewMockGoodEvidence(height int64, index int, address []byte) MockGoodEvidence {
|
||||
return MockGoodEvidence{height, address, index}
|
||||
func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence {
|
||||
return MockGoodEvidence{height, address}
|
||||
}
|
||||
|
||||
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
||||
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
||||
func (e MockGoodEvidence) Index() int { return e.Index_ }
|
||||
func (e MockGoodEvidence) Hash() []byte {
|
||||
return []byte(fmt.Sprintf("%d-%d", e.Height_, e.Index_))
|
||||
return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_))
|
||||
}
|
||||
func (e MockGoodEvidence) Verify(chainID string) error { return nil }
|
||||
func (e MockGoodEvidence) Verify(chainID string, pubKey crypto.PubKey) error { return nil }
|
||||
func (e MockGoodEvidence) Equal(ev Evidence) bool {
|
||||
e2 := ev.(MockGoodEvidence)
|
||||
return e.Height_ == e2.Height_ &&
|
||||
bytes.Equal(e.Address_, e2.Address_) &&
|
||||
e.Index_ == e2.Index_
|
||||
bytes.Equal(e.Address_, e2.Address_)
|
||||
}
|
||||
func (e MockGoodEvidence) String() string {
|
||||
return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
||||
return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_)
|
||||
}
|
||||
|
||||
// UNSTABLE
|
||||
@ -161,15 +160,16 @@ type MockBadEvidence struct {
|
||||
MockGoodEvidence
|
||||
}
|
||||
|
||||
func (e MockBadEvidence) Verify(chainID string) error { return fmt.Errorf("MockBadEvidence") }
|
||||
func (e MockBadEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
return fmt.Errorf("MockBadEvidence")
|
||||
}
|
||||
func (e MockBadEvidence) Equal(ev Evidence) bool {
|
||||
e2 := ev.(MockBadEvidence)
|
||||
return e.Height_ == e2.Height_ &&
|
||||
bytes.Equal(e.Address_, e2.Address_) &&
|
||||
e.Index_ == e2.Index_
|
||||
bytes.Equal(e.Address_, e2.Address_)
|
||||
}
|
||||
func (e MockBadEvidence) String() string {
|
||||
return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
||||
return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_)
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
@ -59,17 +59,16 @@ func TestEvidence(t *testing.T) {
|
||||
{vote1, badVote, false}, // signed by wrong key
|
||||
}
|
||||
|
||||
pubKey := val.GetPubKey()
|
||||
for _, c := range cases {
|
||||
ev := &DuplicateVoteEvidence{
|
||||
PubKey: val.GetPubKey(),
|
||||
VoteA: c.vote1,
|
||||
VoteB: c.vote2,
|
||||
VoteA: c.vote1,
|
||||
VoteB: c.vote2,
|
||||
}
|
||||
if c.valid {
|
||||
assert.Nil(t, ev.Verify(chainID), "evidence should be valid")
|
||||
assert.Nil(t, ev.Verify(chainID, pubKey), "evidence should be valid")
|
||||
} else {
|
||||
assert.NotNil(t, ev.Verify(chainID), "evidence should be invalid")
|
||||
assert.NotNil(t, ev.Verify(chainID, pubKey), "evidence should be invalid")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package types
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
@ -75,34 +76,37 @@ func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams {
|
||||
}
|
||||
}
|
||||
|
||||
func (tm2pb) Evidence(ev_ Evidence) abci.Evidence {
|
||||
switch ev := ev_.(type) {
|
||||
case *DuplicateVoteEvidence:
|
||||
return abci.Evidence{
|
||||
Type: "duplicate/vote",
|
||||
Validator: abci.Validator{
|
||||
Address: ev.Address(),
|
||||
// TODO
|
||||
},
|
||||
Height: ev.Height(),
|
||||
// Time: ev.Time(),
|
||||
// TotalVotingPower: 10,
|
||||
}
|
||||
case *MockGoodEvidence, MockGoodEvidence:
|
||||
return abci.Evidence{
|
||||
Type: "mock/good",
|
||||
Validator: abci.Validator{
|
||||
Address: ev.Address(),
|
||||
// TODO
|
||||
},
|
||||
Height: ev.Height(),
|
||||
// Time: ev.Time(),
|
||||
// TotalVotingPower: 10,
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown evidence type: %v %v", ev_, reflect.TypeOf(ev_)))
|
||||
// ABCI Evidence includes information from the past that's not included in the evidence itself
|
||||
// so Evidence types stays compact.
|
||||
func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.Evidence {
|
||||
_, val := valSet.GetByAddress(ev.Address())
|
||||
if val == nil {
|
||||
// should already have checked this
|
||||
panic(val)
|
||||
}
|
||||
|
||||
abciEvidence := abci.Evidence{
|
||||
Validator: abci.Validator{
|
||||
Address: ev.Address(),
|
||||
PubKey: TM2PB.PubKey(val.PubKey),
|
||||
Power: val.VotingPower,
|
||||
},
|
||||
Height: ev.Height(),
|
||||
Time: evTime.Unix(),
|
||||
TotalVotingPower: valSet.TotalVotingPower(),
|
||||
}
|
||||
|
||||
// set type
|
||||
switch ev.(type) {
|
||||
case *DuplicateVoteEvidence:
|
||||
abciEvidence.Type = "duplicate/vote"
|
||||
case *MockGoodEvidence, MockGoodEvidence:
|
||||
abciEvidence.Type = "mock/good"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev)))
|
||||
}
|
||||
|
||||
return abciEvidence
|
||||
}
|
||||
|
||||
func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator {
|
||||
|
Loading…
x
Reference in New Issue
Block a user