github.com/516108736/tendermint@v0.36.0/consensus/invalid_test.go (about) 1 package consensus 2 3 import ( 4 "testing" 5 6 "github.com/tendermint/tendermint/libs/bytes" 7 "github.com/tendermint/tendermint/libs/log" 8 tmrand "github.com/tendermint/tendermint/libs/rand" 9 "github.com/tendermint/tendermint/p2p" 10 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 11 "github.com/tendermint/tendermint/types" 12 ) 13 14 //---------------------------------------------- 15 // byzantine failures 16 17 // one byz val sends a precommit for a random block at each height 18 // Ensure a testnet makes blocks 19 func TestReactorInvalidPrecommit(t *testing.T) { 20 N := 4 21 css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) 22 defer cleanup() 23 24 for i := 0; i < 4; i++ { 25 ticker := NewTimeoutTicker() 26 ticker.SetLogger(css[i].Logger) 27 css[i].SetTimeoutTicker(ticker) 28 29 } 30 31 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N) 32 33 // this val sends a random precommit at each height 34 byzValIdx := 0 35 byzVal := css[byzValIdx] 36 byzR := reactors[byzValIdx] 37 38 // update the doPrevote function to just send a valid precommit for a random block 39 // and otherwise disable the priv validator 40 byzVal.mtx.Lock() 41 pv := byzVal.privValidator 42 byzVal.doPrevote = func(height int64, round int32) { 43 invalidDoPrevoteFunc(t, height, round, byzVal, byzR.Switch, pv) 44 } 45 byzVal.mtx.Unlock() 46 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 47 48 // wait for a bunch of blocks 49 // TODO: make this tighter by ensuring the halt happens by block 2 50 for i := 0; i < 10; i++ { 51 timeoutWaitGroup(t, N, func(j int) { 52 <-blocksSubs[j].Out() 53 }, css) 54 } 55 } 56 57 func invalidDoPrevoteFunc(t *testing.T, height int64, round int32, cs *State, sw *p2p.Switch, pv types.PrivValidator) { 58 // routine to: 59 // - precommit for a random block 60 // - send precommit to all peers 61 // - disable privValidator (so we don't do normal precommits) 62 go func() { 63 cs.mtx.Lock() 64 cs.privValidator = pv 65 pubKey, err := cs.privValidator.GetPubKey() 66 if err != nil { 67 panic(err) 68 } 69 addr := pubKey.Address() 70 valIndex, _ := cs.Validators.GetByAddress(addr) 71 72 // precommit a random block 73 blockHash := bytes.HexBytes(tmrand.Bytes(32)) 74 precommit := &types.Vote{ 75 ValidatorAddress: addr, 76 ValidatorIndex: valIndex, 77 Height: cs.Height, 78 Round: cs.Round, 79 Timestamp: cs.voteTime(), 80 Type: tmproto.PrecommitType, 81 BlockID: types.BlockID{ 82 Hash: blockHash, 83 PartSetHeader: types.PartSetHeader{Total: 1, Hash: tmrand.Bytes(32)}}, 84 } 85 p := precommit.ToProto() 86 err = cs.privValidator.SignVote(cs.state.ChainID, p) 87 if err != nil { 88 t.Error(err) 89 } 90 precommit.Signature = p.Signature 91 cs.privValidator = nil // disable priv val so we don't do normal votes 92 cs.mtx.Unlock() 93 94 peers := sw.Peers().List() 95 for _, peer := range peers { 96 cs.Logger.Info("Sending bad vote", "block", blockHash, "peer", peer) 97 peer.Send(VoteChannel, MustEncode(&VoteMessage{precommit})) 98 } 99 }() 100 }