mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-09 06:33:16 +00:00
Replace defer with t.Cleanup(). Replace the combination of ioutil.TempDir, error checking and defer os.RemoveAll() with Go testing.T's new TempDir() helper. Mark auxiliary functions as test helpers.
101 lines
2.9 KiB
Go
101 lines
2.9 KiB
Go
package consensus
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/tendermint/tendermint/libs/bytes"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
tmrand "github.com/tendermint/tendermint/libs/rand"
|
|
"github.com/tendermint/tendermint/p2p"
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
//----------------------------------------------
|
|
// byzantine failures
|
|
|
|
// one byz val sends a precommit for a random block at each height
|
|
// Ensure a testnet makes blocks
|
|
func TestReactorInvalidPrecommit(t *testing.T) {
|
|
N := 4
|
|
css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter)
|
|
t.Cleanup(cleanup)
|
|
|
|
for i := 0; i < 4; i++ {
|
|
ticker := NewTimeoutTicker()
|
|
ticker.SetLogger(css[i].Logger)
|
|
css[i].SetTimeoutTicker(ticker)
|
|
|
|
}
|
|
|
|
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N)
|
|
|
|
// this val sends a random precommit at each height
|
|
byzValIdx := 0
|
|
byzVal := css[byzValIdx]
|
|
byzR := reactors[byzValIdx]
|
|
|
|
// update the doPrevote function to just send a valid precommit for a random block
|
|
// and otherwise disable the priv validator
|
|
byzVal.mtx.Lock()
|
|
pv := byzVal.privValidator
|
|
byzVal.doPrevote = func(height int64, round int32) {
|
|
invalidDoPrevoteFunc(t, height, round, byzVal, byzR.Switch, pv)
|
|
}
|
|
byzVal.mtx.Unlock()
|
|
t.Cleanup(func() { stopConsensusNet(log.TestingLogger(), reactors, eventBuses) })
|
|
|
|
// wait for a bunch of blocks
|
|
// TODO: make this tighter by ensuring the halt happens by block 2
|
|
for i := 0; i < 10; i++ {
|
|
timeoutWaitGroup(t, N, func(j int) {
|
|
<-blocksSubs[j].Out()
|
|
}, css)
|
|
}
|
|
}
|
|
|
|
func invalidDoPrevoteFunc(t *testing.T, height int64, round int32, cs *State, sw *p2p.Switch, pv types.PrivValidator) {
|
|
// routine to:
|
|
// - precommit for a random block
|
|
// - send precommit to all peers
|
|
// - disable privValidator (so we don't do normal precommits)
|
|
go func() {
|
|
cs.mtx.Lock()
|
|
cs.privValidator = pv
|
|
pubKey, err := cs.privValidator.GetPubKey()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
addr := pubKey.Address()
|
|
valIndex, _ := cs.Validators.GetByAddress(addr)
|
|
|
|
// precommit a random block
|
|
blockHash := bytes.HexBytes(tmrand.Bytes(32))
|
|
precommit := &types.Vote{
|
|
ValidatorAddress: addr,
|
|
ValidatorIndex: valIndex,
|
|
Height: cs.Height,
|
|
Round: cs.Round,
|
|
Timestamp: cs.voteTime(),
|
|
Type: tmproto.PrecommitType,
|
|
BlockID: types.BlockID{
|
|
Hash: blockHash,
|
|
PartSetHeader: types.PartSetHeader{Total: 1, Hash: tmrand.Bytes(32)}},
|
|
}
|
|
p := precommit.ToProto()
|
|
err = cs.privValidator.SignVote(cs.state.ChainID, p)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
precommit.Signature = p.Signature
|
|
cs.privValidator = nil // disable priv val so we don't do normal votes
|
|
cs.mtx.Unlock()
|
|
|
|
peers := sw.Peers().List()
|
|
for _, peer := range peers {
|
|
cs.Logger.Info("Sending bad vote", "block", blockHash, "peer", peer)
|
|
peer.Send(VoteChannel, MustEncode(&VoteMessage{precommit}))
|
|
}
|
|
}()
|
|
}
|