e2e: add evidence tests (#9292)

This commit is contained in:
Callum Waters
2022-08-22 13:33:47 +02:00
committed by GitHub
parent 2d8df1bd4e
commit b37f062619
34 changed files with 925 additions and 200 deletions

View File

@@ -20,7 +20,6 @@ import (
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
@@ -127,7 +126,7 @@ func newReactor(
lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}
thisBlock := sf.MakeBlock(state, blockHeight, lastCommit)
thisBlock := state.MakeBlock(blockHeight, nil, lastCommit, nil, state.Validators.Proposer.Address)
thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)

View File

@@ -188,7 +188,8 @@ func TestReactorWithEvidence(t *testing.T) {
// mock the evidence pool
// everyone includes evidence of another double signing
vIdx := (i + 1) % nValidators
ev := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], config.ChainID())
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], config.ChainID())
require.NoError(t, err)
evpool := &statemocks.EvidencePool{}
evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil)
evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return([]types.Evidence{
@@ -205,7 +206,7 @@ func TestReactorWithEvidence(t *testing.T) {
eventBus := types.NewEventBus()
eventBus.SetLogger(log.TestingLogger().With("module", "events"))
err := eventBus.Start()
err = eventBus.Start()
require.NoError(t, err)
cs.SetEventBus(eventBus)

View File

@@ -22,6 +22,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
"github.com/tendermint/tendermint/internal/test"
"github.com/tendermint/tendermint/libs/log"
tmrand "github.com/tendermint/tendermint/libs/rand"
mempl "github.com/tendermint/tendermint/mempool"
@@ -30,7 +31,6 @@ import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/types"
)
@@ -904,7 +904,7 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) {
genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
state.LastValidators = state.Validators.Copy()
// mode = 0 for committing all the blocks
blocks, err := sf.MakeBlocks(3, &state, privVal)
blocks, err := test.MakeBlocks(3, state, []types.PrivValidator{privVal})
require.NoError(t, err)
store.chain = blocks

View File

@@ -463,10 +463,13 @@ func (evpool *Pool) processConsensusBuffer(state sm.State) {
// Check the height of the conflicting votes and fetch the corresponding time and validator set
// to produce the valid evidence
var dve *types.DuplicateVoteEvidence
var (
dve *types.DuplicateVoteEvidence
err error
)
switch {
case voteSet.VoteA.Height == state.LastBlockHeight:
dve = types.NewDuplicateVoteEvidence(
dve, err = types.NewDuplicateVoteEvidence(
voteSet.VoteA,
voteSet.VoteB,
state.LastBlockTime,
@@ -474,7 +477,8 @@ func (evpool *Pool) processConsensusBuffer(state sm.State) {
)
case voteSet.VoteA.Height < state.LastBlockHeight:
valSet, err := evpool.stateDB.LoadValidators(voteSet.VoteA.Height)
var valSet *types.ValidatorSet
valSet, err = evpool.stateDB.LoadValidators(voteSet.VoteA.Height)
if err != nil {
evpool.logger.Error("failed to load validator set for conflicting votes", "height",
voteSet.VoteA.Height, "err", err,
@@ -486,7 +490,7 @@ func (evpool *Pool) processConsensusBuffer(state sm.State) {
evpool.logger.Error("failed to load block time for conflicting votes", "height", voteSet.VoteA.Height)
continue
}
dve = types.NewDuplicateVoteEvidence(
dve, err = types.NewDuplicateVoteEvidence(
voteSet.VoteA,
voteSet.VoteB,
blockMeta.Header.Time,
@@ -502,6 +506,10 @@ func (evpool *Pool) processConsensusBuffer(state sm.State) {
"state.LastBlockHeight", state.LastBlockHeight)
continue
}
if err != nil {
evpool.logger.Error("error in generating evidence from votes", "err", err)
continue
}
// check if we already have this evidence
if evpool.isPending(dve) {

View File

@@ -13,11 +13,11 @@ import (
"github.com/tendermint/tendermint/evidence"
"github.com/tendermint/tendermint/evidence/mocks"
"github.com/tendermint/tendermint/internal/test"
"github.com/tendermint/tendermint/libs/log"
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
sm "github.com/tendermint/tendermint/state"
smmocks "github.com/tendermint/tendermint/state/mocks"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
@@ -61,7 +61,8 @@ func TestEvidencePoolBasic(t *testing.T) {
assert.Equal(t, 0, len(evs))
assert.Zero(t, size)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime, privVals[0], evidenceChainID)
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime, privVals[0], evidenceChainID)
require.NoError(t, err)
// good evidence
evAdded := make(chan struct{})
@@ -133,8 +134,9 @@ func TestAddExpiredEvidence(t *testing.T) {
for _, tc := range testCases {
tc := tc
t.Run(tc.evDescription, func(t *testing.T) {
ev := types.NewMockDuplicateVoteEvidenceWithValidator(tc.evHeight, tc.evTime, val, evidenceChainID)
err := pool.AddEvidence(ev)
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(tc.evHeight, tc.evTime, val, evidenceChainID)
require.NoError(t, err)
err = pool.AddEvidence(ev)
if tc.expErr {
assert.Error(t, err)
} else {
@@ -149,7 +151,8 @@ func TestReportConflictingVotes(t *testing.T) {
pool, pv := defaultTestPool(t, height)
val := types.NewValidator(pv.PrivKey.PubKey(), 10)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height+1, defaultEvidenceTime, pv, evidenceChainID)
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height+1, defaultEvidenceTime, pv, evidenceChainID)
require.NoError(t, err)
pool.ReportConflictingVotes(ev.VoteA, ev.VoteB)
@@ -185,12 +188,14 @@ func TestEvidencePoolUpdate(t *testing.T) {
state := pool.State()
// create new block (no need to save it to blockStore)
prunedEv := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultEvidenceTime.Add(1*time.Minute),
prunedEv, err := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultEvidenceTime.Add(1*time.Minute),
val, evidenceChainID)
err := pool.AddEvidence(prunedEv)
require.NoError(t, err)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(21*time.Minute),
err = pool.AddEvidence(prunedEv)
require.NoError(t, err)
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(21*time.Minute),
val, evidenceChainID)
require.NoError(t, err)
lastCommit := makeCommit(height, val.PrivKey.PubKey().Address())
block := types.MakeBlock(height+1, []types.Tx{}, lastCommit, []types.Evidence{ev})
// update state (partially)
@@ -215,9 +220,10 @@ func TestEvidencePoolUpdate(t *testing.T) {
func TestVerifyPendingEvidencePasses(t *testing.T) {
var height int64 = 1
pool, val := defaultTestPool(t, height)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute),
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute),
val, evidenceChainID)
err := pool.AddEvidence(ev)
require.NoError(t, err)
err = pool.AddEvidence(ev)
require.NoError(t, err)
err = pool.CheckEvidence(types.EvidenceList{ev})
@@ -227,9 +233,10 @@ func TestVerifyPendingEvidencePasses(t *testing.T) {
func TestVerifyDuplicatedEvidenceFails(t *testing.T) {
var height int64 = 1
pool, val := defaultTestPool(t, height)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute),
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute),
val, evidenceChainID)
err := pool.CheckEvidence(types.EvidenceList{ev, ev})
require.NoError(t, err)
err = pool.CheckEvidence(types.EvidenceList{ev, ev})
if assert.Error(t, err) {
assert.Equal(t, "duplicate evidence", err.(*types.ErrInvalidEvidence).Reason.Error())
}
@@ -312,10 +319,12 @@ func TestRecoverPendingEvidence(t *testing.T) {
pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
require.NoError(t, err)
pool.SetLogger(log.TestingLogger())
goodEvidence := types.NewMockDuplicateVoteEvidenceWithValidator(height,
goodEvidence, err := types.NewMockDuplicateVoteEvidenceWithValidator(height,
defaultEvidenceTime.Add(10*time.Minute), val, evidenceChainID)
expiredEvidence := types.NewMockDuplicateVoteEvidenceWithValidator(int64(1),
require.NoError(t, err)
expiredEvidence, err := types.NewMockDuplicateVoteEvidenceWithValidator(int64(1),
defaultEvidenceTime.Add(1*time.Minute), val, evidenceChainID)
require.NoError(t, err)
err = pool.AddEvidence(goodEvidence)
require.NoError(t, err)
err = pool.AddEvidence(expiredEvidence)
@@ -404,7 +413,7 @@ func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) (*store.Blo
for i := int64(1); i <= state.LastBlockHeight; i++ {
lastCommit := makeCommit(i-1, valAddr)
block := sf.MakeBlock(state, i, lastCommit)
block := state.MakeBlock(i, test.MakeNTxs(i, 1), lastCommit, nil, state.Validators.Proposer.Address)
block.Header.Time = defaultEvidenceTime.Add(time.Duration(i) * time.Minute)
block.Header.Version = tmversion.Consensus{Block: version.BlockProtocol, App: 1}
const parts = 1

View File

@@ -152,9 +152,10 @@ func TestReactorsGossipNoCommittedEvidence(t *testing.T) {
// the first reactor receives three more evidence
evList = make([]types.Evidence, 3)
for i := 0; i < 3; i++ {
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height-3+int64(i),
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height-3+int64(i),
time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), val, state.ChainID)
err := pools[0].AddEvidence(ev)
require.NoError(t, err)
err = pools[0].AddEvidence(ev)
require.NoError(t, err)
evList[i] = ev
}
@@ -327,9 +328,10 @@ func _waitForEvidence(
func sendEvidence(t *testing.T, evpool *evidence.Pool, val types.PrivValidator, n int) types.EvidenceList {
evList := make([]types.Evidence, n)
for i := 0; i < n; i++ {
ev := types.NewMockDuplicateVoteEvidenceWithValidator(int64(i+1),
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(int64(i+1),
time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), val, evidenceChainID)
err := evpool.AddEvidence(ev)
require.NoError(t, err)
err = evpool.AddEvidence(ev)
require.NoError(t, err)
evList[i] = ev
}
@@ -377,12 +379,13 @@ func TestEvidenceVectors(t *testing.T) {
valSet := types.NewValidatorSet([]*types.Validator{val})
dupl := types.NewDuplicateVoteEvidence(
dupl, err := types.NewDuplicateVoteEvidence(
exampleVote(1),
exampleVote(2),
defaultEvidenceTime,
valSet,
)
require.NoError(t, err)
testCases := []struct {
testName string

View File

@@ -412,11 +412,14 @@ func TestVerifyDuplicateVoteEvidence(t *testing.T) {
}
// create good evidence and correct validator power
goodEv := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime, val, chainID)
goodEv, err := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime, val, chainID)
require.NoError(t, err)
goodEv.ValidatorPower = 1
goodEv.TotalVotingPower = 1
badEv := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime, val, chainID)
badTimeEv := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime.Add(1*time.Minute), val, chainID)
badEv, err := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime, val, chainID)
require.NoError(t, err)
badTimeEv, err := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime.Add(1*time.Minute), val, chainID)
require.NoError(t, err)
badTimeEv.ValidatorPower = 1
badTimeEv.TotalVotingPower = 1
state := sm.State{

123
internal/test/block.go Normal file
View File

@@ -0,0 +1,123 @@
package test
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
)
const (
DefaultTestChainID = "test-chain"
)
var (
DefaultTestTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
)
func RandomAddress() []byte {
return crypto.CRandBytes(crypto.AddressSize)
}
func RandomHash() []byte {
return crypto.CRandBytes(tmhash.Size)
}
func MakeBlockID() types.BlockID {
return MakeBlockIDWithHash(RandomHash())
}
func MakeBlockIDWithHash(hash []byte) types.BlockID {
return types.BlockID{
Hash: hash,
PartSetHeader: types.PartSetHeader{
Total: 100,
Hash: RandomHash(),
},
}
}
// MakeHeader fills the rest of the contents of the header such that it passes
// validate basic
func MakeHeader(t *testing.T, h *types.Header) *types.Header {
t.Helper()
if h.Version.Block == 0 {
h.Version.Block = version.BlockProtocol
}
if h.Height == 0 {
h.Height = 1
}
if h.LastBlockID.IsZero() {
h.LastBlockID = MakeBlockID()
}
if h.ChainID == "" {
h.ChainID = DefaultTestChainID
}
if len(h.LastCommitHash) == 0 {
h.LastCommitHash = RandomHash()
}
if len(h.DataHash) == 0 {
h.DataHash = RandomHash()
}
if len(h.ValidatorsHash) == 0 {
h.ValidatorsHash = RandomHash()
}
if len(h.NextValidatorsHash) == 0 {
h.NextValidatorsHash = RandomHash()
}
if len(h.ConsensusHash) == 0 {
h.ConsensusHash = RandomHash()
}
if len(h.AppHash) == 0 {
h.AppHash = RandomHash()
}
if len(h.LastResultsHash) == 0 {
h.LastResultsHash = RandomHash()
}
if len(h.EvidenceHash) == 0 {
h.EvidenceHash = RandomHash()
}
if len(h.ProposerAddress) == 0 {
h.ProposerAddress = RandomAddress()
}
require.NoError(t, h.ValidateBasic())
return h
}
func MakeBlock(state sm.State) *types.Block {
return state.MakeBlock(state.LastBlockHeight+1, MakeNTxs(state.LastBlockHeight+1, 10), new(types.Commit), nil, state.NextValidators.Proposer.Address)
}
func MakeBlocks(n int, state sm.State, privVals []types.PrivValidator) ([]*types.Block, error) {
blockID := MakeBlockID()
blocks := make([]*types.Block, n)
for i := 0; i < n; i++ {
height := state.LastBlockHeight + 1 + int64(i)
lastCommit, err := MakeCommit(blockID, height-1, 0, state.LastValidators, privVals, state.ChainID, state.LastBlockTime)
if err != nil {
return nil, err
}
block := state.MakeBlock(height, MakeNTxs(height, 10), lastCommit, nil, state.LastValidators.Proposer.Address)
blocks[i] = block
state.LastBlockID = blockID
state.LastBlockHeight = height
state.LastBlockTime = state.LastBlockTime.Add(1 * time.Second)
state.LastValidators = state.Validators.Copy()
state.Validators = state.NextValidators.Copy()
state.NextValidators = state.NextValidators.CopyIncrementProposerPriority(1)
state.AppHash = RandomHash()
blockID = MakeBlockIDWithHash(block.Hash())
}
return blocks, nil
}

90
internal/test/commit.go Normal file
View File

@@ -0,0 +1,90 @@
package test
import (
"fmt"
"time"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
func MakeCommitFromVoteSet(blockID types.BlockID, voteSet *types.VoteSet, validators []types.PrivValidator, now time.Time) (*types.Commit, error) {
// all sign
for i := 0; i < len(validators); i++ {
pubKey, err := validators[i].GetPubKey()
if err != nil {
return nil, err
}
vote := &types.Vote{
ValidatorAddress: pubKey.Address(),
ValidatorIndex: int32(i),
Height: voteSet.GetHeight(),
Round: voteSet.GetRound(),
Type: tmproto.PrecommitType,
BlockID: blockID,
Timestamp: now,
}
v := vote.ToProto()
if err := validators[i].SignVote(voteSet.ChainID(), v); err != nil {
return nil, err
}
vote.Signature = v.Signature
if _, err := voteSet.AddVote(vote); err != nil {
return nil, err
}
}
return voteSet.MakeCommit(), nil
}
func MakeVoteSet(lastState sm.State, round int32) *types.VoteSet {
return types.NewVoteSet(lastState.ChainID, lastState.LastBlockHeight+1, round, tmproto.PrecommitType, lastState.NextValidators)
}
func MakeCommit(blockID types.BlockID, height int64, round int32, valSet *types.ValidatorSet, privVals []types.PrivValidator, chainID string, now time.Time) (*types.Commit, error) {
sigs := make([]types.CommitSig, len(valSet.Validators))
for i := 0; i < len(valSet.Validators); i++ {
sigs[i] = types.NewCommitSigAbsent()
}
for _, privVal := range privVals {
pk, err := privVal.GetPubKey()
if err != nil {
return nil, err
}
addr := pk.Address()
idx, _ := valSet.GetByAddress(addr)
if idx < 0 {
return nil, fmt.Errorf("validator with address %s not in validator set", addr)
}
vote := &types.Vote{
ValidatorAddress: addr,
ValidatorIndex: idx,
Height: height,
Round: round,
Type: tmproto.PrecommitType,
BlockID: blockID,
Timestamp: now,
}
v := vote.ToProto()
if err := privVal.SignVote(chainID, v); err != nil {
return nil, err
}
sigs[idx] = types.CommitSig{
BlockIDFlag: types.BlockIDFlagCommit,
ValidatorAddress: addr,
Timestamp: now,
Signature: v.Signature,
}
}
return types.NewCommit(height, round, blockID, sigs), nil
}

6
internal/test/doc.go Normal file
View File

@@ -0,0 +1,6 @@
/*
Package factory provides generation code for common structs in Tendermint.
It is used primarily for the testing of internal components such as statesync,
consensus, blocksync etc..
*/
package test

View File

@@ -0,0 +1,15 @@
package test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/types"
)
func TestMakeHeader(t *testing.T) {
header := MakeHeader(t, &types.Header{})
require.NotNil(t, header)
require.NoError(t, header.ValidateBasic())
}

33
internal/test/genesis.go Normal file
View File

@@ -0,0 +1,33 @@
package test
import (
"time"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types"
)
func GenesisDoc(
config *cfg.Config,
time time.Time,
validators []*types.Validator,
consensusParams *types.ConsensusParams,
) *types.GenesisDoc {
genesisValidators := make([]types.GenesisValidator, len(validators))
for i := range validators {
genesisValidators[i] = types.GenesisValidator{
Power: validators[i].VotingPower,
PubKey: validators[i].PubKey,
}
}
return &types.GenesisDoc{
GenesisTime: time,
InitialHeight: 1,
ChainID: config.ChainID(),
Validators: genesisValidators,
ConsensusParams: consensusParams,
}
}

View File

@@ -1,4 +1,4 @@
package factory
package test
import "github.com/tendermint/tendermint/types"

View File

@@ -0,0 +1,41 @@
package test
import (
"context"
"sort"
"testing"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/types"
)
func Validator(ctx context.Context, votingPower int64) (*types.Validator, types.PrivValidator, error) {
privVal := types.NewMockPV()
pubKey, err := privVal.GetPubKey()
if err != nil {
return nil, nil, err
}
val := types.NewValidator(pubKey, votingPower)
return val, privVal, nil
}
func ValidatorSet(ctx context.Context, t *testing.T, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) {
var (
valz = make([]*types.Validator, numValidators)
privValidators = make([]types.PrivValidator, numValidators)
)
t.Helper()
for i := 0; i < numValidators; i++ {
val, privValidator, err := Validator(ctx, votingPower)
require.NoError(t, err)
valz[i] = val
privValidators[i] = privValidator
}
sort.Sort(types.PrivValidatorsByAddress(privValidators))
return types.NewValidatorSet(valz), privValidators
}

42
internal/test/vote.go Normal file
View File

@@ -0,0 +1,42 @@
package test
import (
"time"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/types"
)
func MakeVote(
val types.PrivValidator,
chainID string,
valIndex int32,
height int64,
round int32,
step int,
blockID types.BlockID,
time time.Time,
) (*types.Vote, error) {
pubKey, err := val.GetPubKey()
if err != nil {
return nil, err
}
v := &types.Vote{
ValidatorAddress: pubKey.Address(),
ValidatorIndex: valIndex,
Height: height,
Round: round,
Type: tmproto.SignedMsgType(step),
BlockID: blockID,
Timestamp: time,
}
vpb := v.ToProto()
if err := val.SignVote(chainID, vpb); err != nil {
return nil, err
}
v.Signature = vpb.Signature
return v, nil
}

View File

@@ -277,7 +277,8 @@ func TestCreateProposalBlock(t *testing.T) {
// than can fit in a block
var currentBytes int64
for currentBytes <= maxEvidenceBytes {
ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), privVals[0], "test-chain")
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), privVals[0], "test-chain")
require.NoError(t, err)
currentBytes += int64(len(ev.Bytes()))
evidencePool.ReportConflictingVotes(ev.VoteA, ev.VoteB)
}

View File

@@ -45,7 +45,9 @@ func newEvidence(t *testing.T, val *privval.FilePV,
validator := types.NewValidator(val.Key.PubKey, 10)
valSet := types.NewValidatorSet([]*types.Validator{validator})
return types.NewDuplicateVoteEvidence(vote, vote2, defaultTestTime, valSet)
ev, err := types.NewDuplicateVoteEvidence(vote, vote2, defaultTestTime, valSet)
require.NoError(t, err)
return ev
}
func makeEvidences(

View File

@@ -17,6 +17,7 @@ import (
"github.com/tendermint/tendermint/crypto/ed25519"
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/test"
"github.com/tendermint/tendermint/libs/log"
mpmocks "github.com/tendermint/tendermint/mempool/mocks"
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
@@ -24,8 +25,6 @@ import (
pmocks "github.com/tendermint/tendermint/proxy/mocks"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/state/mocks"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/test/factory"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/tendermint/tendermint/version"
@@ -60,7 +59,7 @@ func TestApplyBlock(t *testing.T) {
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, sm.EmptyEvidencePool{})
block := sf.MakeBlock(state, 1, new(types.Commit))
block := makeBlock(state, 1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
@@ -116,7 +115,7 @@ func TestBeginBlockValidators(t *testing.T) {
lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs)
// block for height 2
block := sf.MakeBlock(state, 2, lastCommit)
block := makeBlock(state, 2, lastCommit)
_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateStore, 1)
require.Nil(t, err, tc.desc)
@@ -169,7 +168,8 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
}
// we don't need to worry about validating the evidence as long as they pass validate basic
dve := types.NewMockDuplicateVoteEvidenceWithValidator(3, defaultEvidenceTime, privVal, state.ChainID)
dve, err := types.NewMockDuplicateVoteEvidenceWithValidator(3, defaultEvidenceTime, privVal, state.ChainID)
require.NoError(t, err)
dve.ValidatorPower = 1000
lcae := &types.LightClientAttackEvidence{
ConflictingBlock: &types.LightBlock{
@@ -228,7 +228,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, evpool)
block := sf.MakeBlock(state, 1, new(types.Commit))
block := makeBlock(state, 1, new(types.Commit))
block.Evidence = types.EvidenceData{Evidence: ev}
block.Header.EvidenceHash = block.Evidence.Hash()
bps, err := block.MakePartSet(testPartSize)
@@ -246,7 +246,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
func TestProcessProposal(t *testing.T) {
const height = 2
txs := factory.MakeNTxs(height, 10)
txs := test.MakeNTxs(height, 10)
logger := log.NewNopLogger()
app := abcimocks.NewBaseMock()
@@ -273,17 +273,18 @@ func TestProcessProposal(t *testing.T) {
sm.EmptyEvidencePool{},
)
block0 := sf.MakeBlock(state, height-1, new(types.Commit))
block0 := makeBlock(state, height-1, new(types.Commit))
lastCommitSig := []types.CommitSig{}
partSet, err := block0.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)
blockID := types.BlockID{Hash: block0.Hash(), PartSetHeader: partSet.Header()}
voteInfos := []abci.VoteInfo{}
for _, privVal := range privVals {
vote, err := types.MakeVote(height, blockID, state.Validators, privVal, block0.Header.ChainID, time.Now())
require.NoError(t, err)
pk, err := privVal.GetPubKey()
require.NoError(t, err)
idx, _ := state.Validators.GetByAddress(pk.Address())
vote, err := test.MakeVote(privVal, block0.Header.ChainID, idx, height-1, 0, 2, blockID, time.Now())
require.NoError(t, err)
addr := pk.Address()
voteInfos = append(voteInfos,
abci.VoteInfo{
@@ -296,7 +297,7 @@ func TestProcessProposal(t *testing.T) {
lastCommitSig = append(lastCommitSig, vote.CommitSig())
}
block1 := sf.MakeBlock(state, height, &types.Commit{
block1 := makeBlock(state, height, &types.Commit{
Height: height - 1,
Signatures: lastCommitSig,
})
@@ -499,7 +500,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
)
require.NoError(t, err)
block := sf.MakeBlock(state, 1, new(types.Commit))
block := makeBlock(state, 1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
@@ -557,7 +558,7 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
sm.EmptyEvidencePool{},
)
block := sf.MakeBlock(state, 1, new(types.Commit))
block := makeBlock(state, 1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
@@ -624,7 +625,7 @@ func TestPrepareProposalTxsAllIncluded(t *testing.T) {
evpool := &mocks.EvidencePool{}
evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0))
txs := factory.MakeNTxs(height, 10)
txs := test.MakeNTxs(height, 10)
mp := &mpmocks.Mempool{}
mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs[2:]))
@@ -669,7 +670,7 @@ func TestPrepareProposalReorderTxs(t *testing.T) {
evpool := &mocks.EvidencePool{}
evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0))
txs := factory.MakeNTxs(height, 10)
txs := test.MakeNTxs(height, 10)
mp := &mpmocks.Mempool{}
mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs))
@@ -723,7 +724,7 @@ func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) {
const nValidators = 1
var bytesPerTx int64 = 3
maxDataBytes := types.MaxDataBytes(state.ConsensusParams.Block.MaxBytes, 0, nValidators)
txs := factory.MakeNTxs(height, maxDataBytes/bytesPerTx+2) // +2 so that tx don't fit
txs := test.MakeNTxs(height, maxDataBytes/bytesPerTx+2) // +2 so that tx don't fit
mp := &mpmocks.Mempool{}
mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs))
@@ -767,7 +768,7 @@ func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) {
evpool := &mocks.EvidencePool{}
evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0))
txs := factory.MakeNTxs(height, 10)
txs := test.MakeNTxs(height, 10)
mp := &mpmocks.Mempool{}
mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs))

View File

@@ -11,12 +11,11 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/internal/test"
tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/test/factory"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
@@ -56,7 +55,7 @@ func makeAndCommitGoodBlock(
func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte,
blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) {
block := state.MakeBlock(height, factory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr)
block := state.MakeBlock(height, test.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr)
partSet, err := block.MakePartSet(types.BlockPartSizeBytes)
if err != nil {
return state, types.BlockID{}, err
@@ -74,6 +73,16 @@ func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commi
return state, blockID, nil
}
func makeBlock(state sm.State, height int64, c *types.Commit) *types.Block {
return state.MakeBlock(
height,
test.MakeNTxs(state.LastBlockHeight, 10),
c,
nil,
state.Validators.GetProposer().Address,
)
}
func makeValidCommit(
height int64,
blockID types.BlockID,
@@ -144,7 +153,7 @@ func makeHeaderPartsResponsesValPubKeyChange(
pubkey crypto.PubKey,
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
block := makeBlock(state, state.LastBlockHeight+1, new(types.Commit))
abciResponses := &tmstate.ABCIResponses{
BeginBlock: &abci.ResponseBeginBlock{},
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
@@ -169,7 +178,7 @@ func makeHeaderPartsResponsesValPowerChange(
power int64,
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
block := makeBlock(state, state.LastBlockHeight+1, new(types.Commit))
abciResponses := &tmstate.ABCIResponses{
BeginBlock: &abci.ResponseBeginBlock{},
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
@@ -194,7 +203,7 @@ func makeHeaderPartsResponsesParams(
params tmproto.ConsensusParams,
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
block := makeBlock(state, state.LastBlockHeight+1, new(types.Commit))
abciResponses := &tmstate.ABCIResponses{
BeginBlock: &abci.ResponseBeginBlock{},
EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: &params},

View File

@@ -234,20 +234,20 @@ func FromProto(pb *tmstate.State) (*State, error) { //nolint:golint
func (state State) MakeBlock(
height int64,
txs []types.Tx,
commit *types.Commit,
lastCommit *types.Commit,
evidence []types.Evidence,
proposerAddress []byte,
) *types.Block {
// Build base block with block data.
block := types.MakeBlock(height, txs, commit, evidence)
block := types.MakeBlock(height, txs, lastCommit, evidence)
// Set time.
var timestamp time.Time
if height == state.InitialHeight {
timestamp = state.LastBlockTime // genesis time
} else {
timestamp = MedianTime(commit, state.LastValidators)
timestamp = MedianTime(lastCommit, state.LastValidators)
}
// Fill rest of header with state data.

View File

@@ -20,7 +20,6 @@ import (
tmrand "github.com/tendermint/tendermint/libs/rand"
tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/types"
)
@@ -101,7 +100,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
state.LastBlockHeight++
// Build mock responses.
block := sf.MakeBlock(state, 2, new(types.Commit))
block := makeBlock(state, 2, new(types.Commit))
abciResponses := new(tmstate.ABCIResponses)
dtxs := make([]*abci.ResponseDeliverTx, 2)
@@ -443,7 +442,7 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) {
// NewValidatorSet calls IncrementProposerPriority but uses on a copy of val1
assert.EqualValues(t, 0, val1.ProposerPriority)
block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
block := makeBlock(state, state.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
@@ -559,7 +558,7 @@ func TestProposerPriorityProposerAlternates(t *testing.T) {
// we only have one validator:
assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address)
block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
block := makeBlock(state, state.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
@@ -748,7 +747,7 @@ func TestLargeGenesisValidator(t *testing.T) {
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
require.NoError(t, err)
block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
block := makeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
@@ -779,7 +778,7 @@ func TestLargeGenesisValidator(t *testing.T) {
BeginBlock: &abci.ResponseBeginBlock{},
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}},
}
block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
block := makeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
@@ -798,7 +797,7 @@ func TestLargeGenesisValidator(t *testing.T) {
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
require.NoError(t, err)
block := sf.MakeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit))
block := makeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit))
bps, err = block.MakePartSet(testPartSize)
require.NoError(t, err)
@@ -835,7 +834,7 @@ func TestLargeGenesisValidator(t *testing.T) {
BeginBlock: &abci.ResponseBeginBlock{},
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}},
}
block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
block := makeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
@@ -854,7 +853,7 @@ func TestLargeGenesisValidator(t *testing.T) {
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}},
}
block = sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
block = makeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit))
require.NoError(t, err)
bps, err = block.MakePartSet(testPartSize)
@@ -880,7 +879,7 @@ func TestLargeGenesisValidator(t *testing.T) {
}
validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
require.NoError(t, err)
block = sf.MakeBlock(curState, curState.LastBlockHeight+1, new(types.Commit))
block = makeBlock(curState, curState.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
@@ -909,7 +908,7 @@ func TestLargeGenesisValidator(t *testing.T) {
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
require.NoError(t, err)
block := sf.MakeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit))
block := makeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
@@ -1008,7 +1007,7 @@ func TestStateMakeBlock(t *testing.T) {
proposerAddress := state.Validators.GetProposer().Address
stateVersion := state.Version.Consensus
block := sf.MakeBlock(state, 2, new(types.Commit))
block := makeBlock(state, 2, new(types.Commit))
// test we set some fields
assert.Equal(t, stateVersion, block.Version)

View File

@@ -1,75 +0,0 @@
package factory
import (
"time"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/test/factory"
"github.com/tendermint/tendermint/types"
)
func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) ([]*types.Block, error) {
blocks := make([]*types.Block, n)
var (
prevBlock *types.Block
prevBlockMeta *types.BlockMeta
)
appHeight := byte(0x01)
for i := 0; i < n; i++ {
height := int64(i + 1)
block, parts, err := makeBlockAndPartSet(*state, prevBlock, prevBlockMeta, privVal, height)
if err != nil {
return nil, err
}
blocks[i] = block
prevBlock = block
prevBlockMeta = types.NewBlockMeta(block, parts)
// update state
state.AppHash = []byte{appHeight}
appHeight++
state.LastBlockHeight = height
}
return blocks, nil
}
func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block {
return state.MakeBlock(
height,
factory.MakeNTxs(state.LastBlockHeight, 10),
c,
nil,
state.Validators.GetProposer().Address,
)
}
func makeBlockAndPartSet(
state sm.State,
lastBlock *types.Block,
lastBlockMeta *types.BlockMeta,
privVal types.PrivValidator,
height int64,
) (*types.Block, *types.PartSet, error) {
lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
if height > 1 {
vote, _ := types.MakeVote(
lastBlock.Header.Height,
lastBlockMeta.BlockID,
state.Validators,
privVal,
lastBlock.Header.ChainID,
time.Now())
lastCommit = types.NewCommit(vote.Height, vote.Round,
lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}
block := state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address)
partSet, err := block.MakePartSet(types.BlockPartSizeBytes)
return block, partSet, err
}

View File

@@ -11,13 +11,12 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/test"
"github.com/tendermint/tendermint/libs/log"
mpmocks "github.com/tendermint/tendermint/mempool/mocks"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/state/mocks"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/test/factory"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
@@ -91,7 +90,7 @@ func TestValidateBlockHeader(t *testing.T) {
Invalid blocks don't pass
*/
for _, tc := range testCases {
block := sf.MakeBlock(state, height, lastCommit)
block := makeBlock(state, height, lastCommit)
tc.malleateBlock(block)
err := blockExec.ValidateBlock(state, block)
require.Error(t, err, tc.name)
@@ -144,12 +143,15 @@ func TestValidateBlockCommit(t *testing.T) {
#2589: ensure state.LastValidators.VerifyCommit fails here
*/
// should be height-1 instead of height
wrongHeightVote, err := types.MakeVote(
height,
state.LastBlockID,
state.Validators,
idx, _ := state.Validators.GetByAddress(proposerAddr)
wrongHeightVote, err := test.MakeVote(
privVals[proposerAddr.String()],
chainID,
idx,
height,
0,
2,
state.LastBlockID,
time.Now(),
)
require.NoError(t, err, "height %d", height)
@@ -159,7 +161,7 @@ func TestValidateBlockCommit(t *testing.T) {
state.LastBlockID,
[]types.CommitSig{wrongHeightVote.CommitSig()},
)
block := sf.MakeBlock(state, height, wrongHeightCommit)
block := makeBlock(state, height, wrongHeightCommit)
err = blockExec.ValidateBlock(state, block)
_, isErrInvalidCommitHeight := err.(types.ErrInvalidCommitHeight)
require.True(t, isErrInvalidCommitHeight, "expected ErrInvalidCommitHeight at height %d but got: %v", height, err)
@@ -167,7 +169,7 @@ func TestValidateBlockCommit(t *testing.T) {
/*
#2589: test len(block.LastCommit.Signatures) == state.LastValidators.Size()
*/
block = sf.MakeBlock(state, height, wrongSigsCommit)
block = makeBlock(state, height, wrongSigsCommit)
err = blockExec.ValidateBlock(state, block)
_, isErrInvalidCommitSignatures := err.(types.ErrInvalidCommitSignatures)
require.True(t, isErrInvalidCommitSignatures,
@@ -280,12 +282,13 @@ func TestValidateBlockEvidence(t *testing.T) {
var currentBytes int64
// more bytes than the maximum allowed for evidence
for currentBytes <= maxBytesEvidence {
newEv := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(),
newEv, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(),
privVals[proposerAddr.String()], chainID)
require.NoError(t, err)
evidence = append(evidence, newEv)
currentBytes += int64(len(newEv.Bytes()))
}
block := state.MakeBlock(height, factory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr)
block := state.MakeBlock(height, test.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr)
err := blockExec.ValidateBlock(state, block)
if assert.Error(t, err) {
@@ -301,8 +304,9 @@ func TestValidateBlockEvidence(t *testing.T) {
var currentBytes int64
// precisely the amount of allowed evidence
for {
newEv := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime,
newEv, err := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime,
privVals[proposerAddr.String()], chainID)
require.NoError(t, err)
currentBytes += int64(len(newEv.Bytes()))
if currentBytes >= maxBytesEvidence {
break

View File

@@ -17,12 +17,12 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/internal/test"
"github.com/tendermint/tendermint/libs/log"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmstore "github.com/tendermint/tendermint/proto/tendermint/store"
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/tendermint/tendermint/version"
@@ -136,7 +136,7 @@ func TestMain(m *testing.M) {
var cleanup cleanupFunc
var err error
state, _, cleanup = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
block = factory.MakeBlock(state, 1, new(types.Commit))
block = state.MakeBlock(state.LastBlockHeight+1, test.MakeNTxs(state.LastBlockHeight+1, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
partSet, err = block.MakePartSet(2)
if err != nil {
@@ -167,7 +167,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
}
// save a block
block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit))
block := state.MakeBlock(bs.Height()+1, nil, new(types.Commit), nil, state.Validators.GetProposer().Address)
validPartSet, err := block.MakePartSet(2)
require.NoError(t, err)
seenCommit := makeTestCommit(10, tmtime.Now())
@@ -371,7 +371,7 @@ func TestLoadBaseMeta(t *testing.T) {
bs := NewBlockStore(dbm.NewMemDB())
for h := int64(1); h <= 10; h++ {
block := factory.MakeBlock(state, h, new(types.Commit))
block := state.MakeBlock(h, test.MakeNTxs(h, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
partSet, err := block.MakePartSet(2)
require.NoError(t, err)
seenCommit := makeTestCommit(h, tmtime.Now())
@@ -440,7 +440,7 @@ func TestPruneBlocks(t *testing.T) {
// make more than 1000 blocks, to test batch deletions
for h := int64(1); h <= 1500; h++ {
block := factory.MakeBlock(state, h, new(types.Commit))
block := state.MakeBlock(h, test.MakeNTxs(h, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
partSet, err := block.MakePartSet(2)
require.NoError(t, err)
seenCommit := makeTestCommit(h, tmtime.Now())
@@ -550,7 +550,7 @@ func TestBlockFetchAtHeight(t *testing.T) {
state, bs, cleanup := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
defer cleanup()
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit))
block := state.MakeBlock(bs.Height()+1, nil, new(types.Commit), nil, state.Validators.GetProposer().Address)
partSet, err := block.MakePartSet(2)
require.NoError(t, err)

View File

@@ -3,6 +3,7 @@
ipv6 = true
initial_height = 1000
evidence = 5
initial_state = { initial01 = "a", initial02 = "b", initial03 = "c" }
prepare_proposal_delay = "100ms"
process_proposal_delay = "100ms"
@@ -30,11 +31,7 @@ validator05 = 50
[node.seed01]
mode = "seed"
seeds = ["seed02"]
[node.seed02]
mode = "seed"
seeds = ["seed01"]
perturb = ["restart"]
[node.validator01]
seeds = ["seed01"]
@@ -42,7 +39,7 @@ snapshot_interval = 5
perturb = ["disconnect"]
[node.validator02]
seeds = ["seed02"]
seeds = ["seed01"]
database = "boltdb"
abci_protocol = "tcp"
privval_protocol = "tcp"
@@ -56,7 +53,7 @@ database = "badgerdb"
#abci_protocol = "grpc"
privval_protocol = "unix"
persist_interval = 3
retain_blocks = 3
retain_blocks = 10
perturb = ["kill"]
[node.validator04]
@@ -67,7 +64,7 @@ perturb = ["pause"]
[node.validator05]
start_at = 1005 # Becomes part of the validator set at 1010
seeds = ["seed02"]
persistent_peers = ["validator01", "full01"]
database = "cleveldb"
fast_sync = true
mempool_version = "v1"
@@ -81,7 +78,7 @@ start_at = 1010
mode = "full"
fast_sync = true
persistent_peers = ["validator01", "validator02", "validator03", "validator04", "validator05"]
retain_blocks = 1
retain_blocks = 10
perturb = ["restart"]
[node.full02]

View File

@@ -52,6 +52,10 @@ type Manifest struct {
// Options are ed25519 & secp256k1
KeyType string `toml:"key_type"`
// Evidence indicates the amount of evidence that will be injected into the
// testnet via the RPC endpoint of a random node. Default is 0
Evidence int `toml:"evidence"`
// ABCIProtocol specifies the protocol used to communicate with the ABCI
// application: "unix", "tcp", "grpc", or "builtin". Defaults to builtin.
// builtin will build a complete Tendermint node into the application and

View File

@@ -46,6 +46,9 @@ const (
PerturbationKill Perturbation = "kill"
PerturbationPause Perturbation = "pause"
PerturbationRestart Perturbation = "restart"
EvidenceAgeHeight int64 = 7
EvidenceAgeTime time.Duration = 500 * time.Millisecond
)
// Testnet represents a single testnet.
@@ -60,6 +63,7 @@ type Testnet struct {
ValidatorUpdates map[int64]map[*Node]int64
Nodes []*Node
KeyType string
Evidence int
ABCIProtocol string
PrepareProposalDelay time.Duration
ProcessProposalDelay time.Duration
@@ -126,6 +130,7 @@ func LoadTestnet(file string) (*Testnet, error) {
Validators: map[*Node]int64{},
ValidatorUpdates: map[int64]map[*Node]int64{},
Nodes: []*Node{},
Evidence: manifest.Evidence,
ABCIProtocol: manifest.ABCIProtocol,
PrepareProposalDelay: manifest.PrepareProposalDelay,
ProcessProposalDelay: manifest.ProcessProposalDelay,
@@ -335,6 +340,10 @@ func (n Node) Validate(testnet Testnet) error {
if n.StateSync && n.StartAt == 0 {
return errors.New("state synced nodes cannot start at the initial height")
}
if n.RetainBlocks != 0 && n.RetainBlocks < uint64(EvidenceAgeHeight) {
return fmt.Errorf("retain_blocks must be greater or equal to max evidence age (%d)",
EvidenceAgeHeight)
}
if n.PersistInterval == 0 && n.RetainBlocks > 0 {
return errors.New("persist_interval=0 requires retain_blocks=0")
}

320
test/e2e/runner/evidence.go Normal file
View File

@@ -0,0 +1,320 @@
package main
import (
"bytes"
"context"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"path/filepath"
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/test"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tendermint/tendermint/privval"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
e2e "github.com/tendermint/tendermint/test/e2e/pkg"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
)
// 1 in 4 evidence is light client evidence, the rest is duplicate vote evidence
const lightClientEvidenceRatio = 4
// InjectEvidence takes a running testnet and generates an amount of valid
// evidence and broadcasts it to a random node through the rpc endpoint `/broadcast_evidence`.
// Evidence is random and can be a mixture of LightClientAttackEvidence and
// DuplicateVoteEvidence.
func InjectEvidence(ctx context.Context, r *rand.Rand, testnet *e2e.Testnet, amount int) error {
// select a random node
var targetNode *e2e.Node
for _, idx := range r.Perm(len(testnet.Nodes)) {
targetNode = testnet.Nodes[idx]
if targetNode.Mode == e2e.ModeSeed || targetNode.Mode == e2e.ModeLight {
targetNode = nil
continue
}
break
}
if targetNode == nil {
return errors.New("could not find node to inject evidence into")
}
logger.Info(fmt.Sprintf("Injecting evidence through %v (amount: %d)...", targetNode.Name, amount))
client, err := targetNode.Client()
if err != nil {
return err
}
// request the latest block and validator set from the node
blockRes, err := client.Block(ctx, nil)
if err != nil {
return err
}
evidenceHeight := blockRes.Block.Height
waitHeight := blockRes.Block.Height + 3
nValidators := 100
valRes, err := client.Validators(ctx, &evidenceHeight, nil, &nValidators)
if err != nil {
return err
}
valSet, err := types.ValidatorSetFromExistingValidators(valRes.Validators)
if err != nil {
return err
}
// get the private keys of all the validators in the network
privVals, err := getPrivateValidatorKeys(testnet)
if err != nil {
return err
}
// wait for the node to reach the height above the forged height so that
// it is able to validate the evidence
_, err = waitForNode(targetNode, waitHeight, time.Minute)
if err != nil {
return err
}
var ev types.Evidence
for i := 1; i <= amount; i++ {
if i%lightClientEvidenceRatio == 0 {
ev, err = generateLightClientAttackEvidence(
ctx, privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time,
)
} else {
ev, err = generateDuplicateVoteEvidence(
ctx, privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time,
)
}
if err != nil {
return err
}
_, err := client.BroadcastEvidence(ctx, ev)
if err != nil {
return err
}
}
// wait for the node to reach the height above the forged height so that
// it is able to validate the evidence
_, err = waitForNode(targetNode, blockRes.Block.Height+2, 30*time.Second)
if err != nil {
return err
}
logger.Info(fmt.Sprintf("Finished sending evidence (height %d)", blockRes.Block.Height+2))
return nil
}
func getPrivateValidatorKeys(testnet *e2e.Testnet) ([]types.MockPV, error) {
privVals := []types.MockPV{}
for _, node := range testnet.Nodes {
if node.Mode == e2e.ModeValidator {
privKeyPath := filepath.Join(testnet.Dir, node.Name, PrivvalKeyFile)
privKey, err := readPrivKey(privKeyPath)
if err != nil {
return nil, err
}
// Create mock private validators from the validators private key. MockPV is
// stateless which means we can double vote and do other funky stuff
privVals = append(privVals, types.NewMockPVWithParams(privKey, false, false))
}
}
return privVals, nil
}
// creates evidence of a lunatic attack. The height provided is the common height.
// The forged height happens 2 blocks later.
func generateLightClientAttackEvidence(
ctx context.Context,
privVals []types.MockPV,
height int64,
vals *types.ValidatorSet,
chainID string,
evTime time.Time,
) (*types.LightClientAttackEvidence, error) {
// forge a random header
forgedHeight := height + 2
forgedTime := evTime.Add(1 * time.Second)
header := makeHeaderRandom(chainID, forgedHeight)
header.Time = forgedTime
// add a new bogus validator and remove an existing one to
// vary the validator set slightly
pv, conflictingVals, err := mutateValidatorSet(ctx, privVals, vals)
if err != nil {
return nil, err
}
header.ValidatorsHash = conflictingVals.Hash()
// create a commit for the forged header
blockID := makeBlockID(header.Hash(), 1000, []byte("partshash"))
voteSet := types.NewVoteSet(chainID, forgedHeight, 0, tmproto.SignedMsgType(2), conflictingVals)
commit, err := test.MakeCommitFromVoteSet(blockID, voteSet, pv, forgedTime)
if err != nil {
return nil, err
}
ev := &types.LightClientAttackEvidence{
ConflictingBlock: &types.LightBlock{
SignedHeader: &types.SignedHeader{
Header: header,
Commit: commit,
},
ValidatorSet: conflictingVals,
},
CommonHeight: height,
TotalVotingPower: vals.TotalVotingPower(),
Timestamp: evTime,
}
ev.ByzantineValidators = ev.GetByzantineValidators(vals, &types.SignedHeader{
Header: makeHeaderRandom(chainID, forgedHeight),
})
return ev, nil
}
// generateDuplicateVoteEvidence picks a random validator from the val set and
// returns duplicate vote evidence against the validator
func generateDuplicateVoteEvidence(
ctx context.Context,
privVals []types.MockPV,
height int64,
vals *types.ValidatorSet,
chainID string,
time time.Time,
) (*types.DuplicateVoteEvidence, error) {
privVal, valIdx, err := getRandomValidatorIndex(privVals, vals)
if err != nil {
return nil, err
}
voteA, err := test.MakeVote(privVal, chainID, valIdx, height, 0, 2, makeRandomBlockID(), time)
if err != nil {
return nil, err
}
voteB, err := test.MakeVote(privVal, chainID, valIdx, height, 0, 2, makeRandomBlockID(), time)
if err != nil {
return nil, err
}
ev, err := types.NewDuplicateVoteEvidence(voteA, voteB, time, vals)
if err != nil {
return nil, fmt.Errorf("could not generate evidence: %w", err)
}
return ev, nil
}
// getRandomValidatorIndex picks a random validator from a slice of mock PrivVals that's
// also part of the validator set, returning the PrivVal and its index in the validator set
func getRandomValidatorIndex(privVals []types.MockPV, vals *types.ValidatorSet) (types.MockPV, int32, error) {
for _, idx := range rand.Perm(len(privVals)) {
pv := privVals[idx]
valIdx, _ := vals.GetByAddress(pv.PrivKey.PubKey().Address())
if valIdx >= 0 {
return pv, valIdx, nil
}
}
return types.MockPV{}, -1, errors.New("no private validator found in validator set")
}
func readPrivKey(keyFilePath string) (crypto.PrivKey, error) {
keyJSONBytes, err := ioutil.ReadFile(keyFilePath)
if err != nil {
return nil, err
}
pvKey := privval.FilePVKey{}
err = tmjson.Unmarshal(keyJSONBytes, &pvKey)
if err != nil {
return nil, fmt.Errorf("error reading PrivValidator key from %v: %w", keyFilePath, err)
}
return pvKey.PrivKey, nil
}
func makeHeaderRandom(chainID string, height int64) *types.Header {
return &types.Header{
Version: tmversion.Consensus{Block: version.BlockProtocol, App: 1},
ChainID: chainID,
Height: height,
Time: time.Now(),
LastBlockID: makeBlockID([]byte("headerhash"), 1000, []byte("partshash")),
LastCommitHash: crypto.CRandBytes(tmhash.Size),
DataHash: crypto.CRandBytes(tmhash.Size),
ValidatorsHash: crypto.CRandBytes(tmhash.Size),
NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
ConsensusHash: crypto.CRandBytes(tmhash.Size),
AppHash: crypto.CRandBytes(tmhash.Size),
LastResultsHash: crypto.CRandBytes(tmhash.Size),
EvidenceHash: crypto.CRandBytes(tmhash.Size),
ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
}
}
func makeRandomBlockID() types.BlockID {
return makeBlockID(crypto.CRandBytes(tmhash.Size), 100, crypto.CRandBytes(tmhash.Size))
}
func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID {
var (
h = make([]byte, tmhash.Size)
psH = make([]byte, tmhash.Size)
)
copy(h, hash)
copy(psH, partSetHash)
return types.BlockID{
Hash: h,
PartSetHeader: types.PartSetHeader{
Total: partSetSize,
Hash: psH,
},
}
}
func mutateValidatorSet(ctx context.Context, privVals []types.MockPV, vals *types.ValidatorSet,
) ([]types.PrivValidator, *types.ValidatorSet, error) {
newVal, newPrivVal, err := test.Validator(ctx, 10)
if err != nil {
return nil, nil, err
}
var newVals *types.ValidatorSet
if vals.Size() > 2 {
newVals = types.NewValidatorSet(append(vals.Copy().Validators[:vals.Size()-1], newVal))
} else {
newVals = types.NewValidatorSet(append(vals.Copy().Validators, newVal))
}
// we need to sort the priv validators with the same index as the validator set
pv := make([]types.PrivValidator, newVals.Size())
for idx, val := range newVals.Validators {
found := false
for _, p := range append(privVals, newPrivVal.(types.MockPV)) {
if bytes.Equal(p.PrivKey.PubKey().Address(), val.Address) {
pv[idx] = p
found = true
break
}
}
if !found {
return nil, nil, fmt.Errorf("missing priv validator for %v", val.Address)
}
}
return pv, newVals, nil
}

View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"math/rand"
"os"
"strconv"
@@ -12,9 +13,9 @@ import (
e2e "github.com/tendermint/tendermint/test/e2e/pkg"
)
var (
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
)
const randomSeed = 2308084734268
var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
func main() {
NewCLI().Run()
@@ -56,6 +57,8 @@ func NewCLI() *CLI {
return err
}
r := rand.New(rand.NewSource(randomSeed)) // nolint: gosec
chLoadResult := make(chan error)
ctx, loadCancel := context.WithCancel(context.Background())
defer loadCancel()
@@ -84,6 +87,15 @@ func NewCLI() *CLI {
}
}
if cli.testnet.Evidence > 0 {
if err := InjectEvidence(ctx, r, cli.testnet, cli.testnet.Evidence); err != nil {
return err
}
if err := Wait(cli.testnet, 5); err != nil { // ensure chain progress
return err
}
}
loadCancel()
if err := <-chLoadResult; err != nil {
return err
@@ -175,6 +187,29 @@ func NewCLI() *CLI {
},
})
cli.root.AddCommand(&cobra.Command{
Use: "evidence [amount]",
Args: cobra.MaximumNArgs(1),
Short: "Generates and broadcasts evidence to a random node",
RunE: func(cmd *cobra.Command, args []string) (err error) {
amount := 1
if len(args) == 1 {
amount, err = strconv.Atoi(args[0])
if err != nil {
return err
}
}
return InjectEvidence(
cmd.Context(),
rand.New(rand.NewSource(randomSeed)), // nolint: gosec
cli.testnet,
amount,
)
},
})
cli.root.AddCommand(&cobra.Command{
Use: "test",
Short: "Runs test cases against a running testnet",

View File

@@ -0,0 +1,22 @@
package e2e_test
import (
"testing"
"github.com/stretchr/testify/require"
)
// assert that all nodes that have blocks at the height of a misbehavior has evidence
// for that misbehavior
func TestEvidence_Misbehavior(t *testing.T) {
blocks := fetchBlockChain(t)
testnet := loadTestnet(t)
seenEvidence := 0
for _, block := range blocks {
if len(block.Evidence.Evidence) != 0 {
seenEvidence += len(block.Evidence.Evidence)
}
}
require.Equal(t, testnet.Evidence, seenEvidence,
"difference between the amount of evidence produced and committed")
}

View File

@@ -41,7 +41,8 @@ func TestBlockAddEvidence(t *testing.T) {
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
require.NoError(t, err)
ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
require.NoError(t, err)
evList := []Evidence{ev}
block := MakeBlock(h, txs, commit, evList)
@@ -61,7 +62,8 @@ func TestBlockValidateBasic(t *testing.T) {
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
require.NoError(t, err)
ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
require.NoError(t, err)
evList := []Evidence{ev}
testCases := []struct {
@@ -132,7 +134,8 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) {
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
require.NoError(t, err)
ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
require.NoError(t, err)
evList := []Evidence{ev}
partSet, err := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512)
@@ -151,7 +154,8 @@ func TestBlockHashesTo(t *testing.T) {
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
require.NoError(t, err)
ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
require.NoError(t, err)
evList := []Evidence{ev}
block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList)
@@ -642,7 +646,8 @@ func TestBlockProtoBuf(t *testing.T) {
b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{})
b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize)
evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain")
evi, err := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain")
require.NoError(t, err)
b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}}
b2.EvidenceHash = b2.Evidence.Hash()
@@ -706,7 +711,8 @@ func TestDataProtoBuf(t *testing.T) {
// TestEvidenceDataProtoBuf ensures parity in converting to and from proto.
func TestEvidenceDataProtoBuf(t *testing.T) {
const chainID = "mychain"
ev := NewMockDuplicateVoteEvidence(math.MaxInt64, time.Now(), chainID)
ev, err := NewMockDuplicateVoteEvidence(math.MaxInt64, time.Now(), chainID)
require.NoError(t, err)
data := &EvidenceData{Evidence: EvidenceList{ev}}
_ = data.ByteSize()
testCases := []struct {

View File

@@ -285,7 +285,8 @@ func TestEventBusPublishEventNewEvidence(t *testing.T) {
}
})
ev := NewMockDuplicateVoteEvidence(1, time.Now(), "test-chain-id")
ev, err := NewMockDuplicateVoteEvidence(1, time.Now(), "test-chain-id")
require.NoError(t, err)
query := "tm.event='NewEvidence'"
evSub, err := eventBus.Subscribe(context.Background(), "test", tmquery.MustParse(query))

View File

@@ -45,15 +45,20 @@ type DuplicateVoteEvidence struct {
var _ Evidence = &DuplicateVoteEvidence{}
// NewDuplicateVoteEvidence creates DuplicateVoteEvidence with right ordering given
// two conflicting votes. If one of the votes is nil, evidence returned is nil as well
func NewDuplicateVoteEvidence(vote1, vote2 *Vote, blockTime time.Time, valSet *ValidatorSet) *DuplicateVoteEvidence {
// two conflicting votes. If either of the votes is nil, the val set is nil or the voter is
// not in the val set, an error is returned
func NewDuplicateVoteEvidence(vote1, vote2 *Vote, blockTime time.Time, valSet *ValidatorSet,
) (*DuplicateVoteEvidence, error) {
var voteA, voteB *Vote
if vote1 == nil || vote2 == nil || valSet == nil {
return nil
if vote1 == nil || vote2 == nil {
return nil, errors.New("missing vote")
}
if valSet == nil {
return nil, errors.New("missing validator set")
}
idx, val := valSet.GetByAddress(vote1.ValidatorAddress)
if idx == -1 {
return nil
return nil, fmt.Errorf("validator %s not in validator set", vote1.ValidatorAddress.String())
}
if strings.Compare(vote1.BlockID.Key(), vote2.BlockID.Key()) == -1 {
@@ -69,7 +74,7 @@ func NewDuplicateVoteEvidence(vote1, vote2 *Vote, blockTime time.Time, valSet *V
TotalVotingPower: valSet.TotalVotingPower(),
ValidatorPower: val.VotingPower,
Timestamp: blockTime,
}
}, nil
}
// ABCI returns the application relevant representation of the evidence
@@ -564,23 +569,32 @@ func (err *ErrEvidenceOverflow) Error() string {
// unstable - use only for testing
// assumes the round to be 0 and the validator index to be 0
func NewMockDuplicateVoteEvidence(height int64, time time.Time, chainID string) *DuplicateVoteEvidence {
func NewMockDuplicateVoteEvidence(height int64, time time.Time, chainID string) (*DuplicateVoteEvidence, error) {
val := NewMockPV()
return NewMockDuplicateVoteEvidenceWithValidator(height, time, val, chainID)
}
// assumes voting power to be 10 and validator to be the only one in the set
func NewMockDuplicateVoteEvidenceWithValidator(height int64, time time.Time,
pv PrivValidator, chainID string) *DuplicateVoteEvidence {
pubKey, _ := pv.GetPubKey()
pv PrivValidator, chainID string) (*DuplicateVoteEvidence, error) {
pubKey, err := pv.GetPubKey()
if err != nil {
return nil, err
}
val := NewValidator(pubKey, 10)
voteA := makeMockVote(height, 0, 0, pubKey.Address(), randBlockID(), time)
vA := voteA.ToProto()
_ = pv.SignVote(chainID, vA)
err = pv.SignVote(chainID, vA)
if err != nil {
return nil, err
}
voteA.Signature = vA.Signature
voteB := makeMockVote(height, 0, 0, pubKey.Address(), randBlockID(), time)
vB := voteB.ToProto()
_ = pv.SignVote(chainID, vB)
err = pv.SignVote(chainID, vB)
if err != nil {
return nil, err
}
voteB.Signature = vB.Signature
return NewDuplicateVoteEvidence(voteA, voteB, time, NewValidatorSet([]*Validator{val}))
}

View File

@@ -43,7 +43,8 @@ func randomDuplicateVoteEvidence(t *testing.T) *DuplicateVoteEvidence {
func TestDuplicateVoteEvidence(t *testing.T) {
const height = int64(13)
ev := NewMockDuplicateVoteEvidence(height, time.Now(), "mock-chain-id")
ev, err := NewMockDuplicateVoteEvidence(height, time.Now(), "mock-chain-id")
require.NoError(t, err)
assert.Equal(t, ev.Hash(), tmhash.Sum(ev.Bytes()))
assert.NotNil(t, ev.String())
assert.Equal(t, ev.Height(), height)
@@ -82,7 +83,8 @@ func TestDuplicateVoteEvidenceValidation(t *testing.T) {
vote1 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID, defaultVoteTime)
vote2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID2, defaultVoteTime)
valSet := NewValidatorSet([]*Validator{val.ExtractIntoValidator(10)})
ev := NewDuplicateVoteEvidence(vote1, vote2, defaultVoteTime, valSet)
ev, err := NewDuplicateVoteEvidence(vote1, vote2, defaultVoteTime, valSet)
require.NoError(t, err)
tc.malleateEvidence(ev)
assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
@@ -224,7 +226,8 @@ func TestLightClientAttackEvidenceValidation(t *testing.T) {
}
func TestMockEvidenceValidateBasic(t *testing.T) {
goodEvidence := NewMockDuplicateVoteEvidence(int64(1), time.Now(), "mock-chain-id")
goodEvidence, err := NewMockDuplicateVoteEvidence(int64(1), time.Now(), "mock-chain-id")
require.NoError(t, err)
assert.Nil(t, goodEvidence.ValidateBasic())
}