- 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}))
- }
- }()
- }
|