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