From 3d2c4fd309e54d3cee9e49e4bb8e3284bda85ec9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jun 2018 15:27:59 -0400 Subject: [PATCH] update Evidence type - requires pubkey and valset to verify and convert to abci.Evidence --- consensus/replay.go | 2 +- state/execution.go | 84 ++++++++++++++++++++++++---------------- state/execution_test.go | 38 +++++++++++------- state/store.go | 5 ++- state/validation.go | 31 ++++++++------- state/validation_test.go | 2 +- types/evidence.go | 56 +++++++++++++-------------- types/evidence_test.go | 11 +++--- types/protobuf.go | 50 +++++++++++++----------- 9 files changed, 157 insertions(+), 122 deletions(-) diff --git a/consensus/replay.go b/consensus/replay.go index c4ee2d32d..b30a1f151 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -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 } diff --git a/state/execution.go b/state/execution.go index b65c2ebd7..370fa0954 100644 --- a/state/execution.go +++ b/state/execution.go @@ -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 diff --git a/state/execution_test.go b/state/execution_test.go index e31a0fd13..b520b0c12 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -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 { diff --git a/state/store.go b/state/store.go index 60acf9e1e..2164d699d 100644 --- a/state/store.go +++ b/state/store.go @@ -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 diff --git a/state/validation.go b/state/validation.go index 0726b61ea..ac133aff2 100644 --- a/state/validation.go +++ b/state/validation.go @@ -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 diff --git a/state/validation_test.go b/state/validation_test.go index f72021975..b4695b077 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -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) diff --git a/types/evidence.go b/types/evidence.go index ee7f44a58..1a823df07 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -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_) } //------------------------------------------- diff --git a/types/evidence_test.go b/types/evidence_test.go index f2b1f91bb..5bbb2a37d 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -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") } } - } diff --git a/types/protobuf.go b/types/protobuf.go index 20cf8a561..608ebb653 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -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) { +// 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: - return abci.Evidence{ - Type: "duplicate/vote", - Validator: abci.Validator{ - Address: ev.Address(), - // TODO - }, - Height: ev.Height(), - // Time: ev.Time(), - // TotalVotingPower: 10, - } + abciEvidence.Type = "duplicate/vote" case *MockGoodEvidence, MockGoodEvidence: - return abci.Evidence{ - Type: "mock/good", - Validator: abci.Validator{ - Address: ev.Address(), - // TODO - }, - Height: ev.Height(), - // Time: ev.Time(), - // TotalVotingPower: 10, - } + abciEvidence.Type = "mock/good" default: - panic(fmt.Sprintf("Unknown evidence type: %v %v", ev_, reflect.TypeOf(ev_))) + panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev))) } + return abciEvidence } func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator {