mirror of
https://github.com/tendermint/tendermint.git
synced 2026-06-04 13:22:35 +00:00
e2e: add evidence tests (#9292)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
123
internal/test/block.go
Normal 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
90
internal/test/commit.go
Normal 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
6
internal/test/doc.go
Normal 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
|
||||
15
internal/test/factory_test.go
Normal file
15
internal/test/factory_test.go
Normal 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
33
internal/test/genesis.go
Normal 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,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package factory
|
||||
package test
|
||||
|
||||
import "github.com/tendermint/tendermint/types"
|
||||
|
||||
41
internal/test/validator.go
Normal file
41
internal/test/validator.go
Normal 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
42
internal/test/vote.go
Normal 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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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: ¶ms},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
320
test/e2e/runner/evidence.go
Normal 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
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
22
test/e2e/tests/evidence_test.go
Normal file
22
test/e2e/tests/evidence_test.go
Normal 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")
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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}))
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user