You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
7.9 KiB

  1. package consensus
  2. import (
  3. "context"
  4. "sync"
  5. "testing"
  6. "time"
  7. "github.com/stretchr/testify/require"
  8. "github.com/tendermint/tendermint/p2p"
  9. "github.com/tendermint/tendermint/types"
  10. cmn "github.com/tendermint/tmlibs/common"
  11. )
  12. func init() {
  13. config = ResetConfig("consensus_byzantine_test")
  14. }
  15. //----------------------------------------------
  16. // byzantine failures
  17. // 4 validators. 1 is byzantine. The other three are partitioned into A (1 val) and B (2 vals).
  18. // byzantine validator sends conflicting proposals into A and B,
  19. // and prevotes/precommits on both of them.
  20. // B sees a commit, A doesn't.
  21. // Byzantine validator refuses to prevote.
  22. // Heal partition and ensure A sees the commit
  23. func TestByzantine(t *testing.T) {
  24. N := 4
  25. logger := consensusLogger().With("test", "byzantine")
  26. css := randConsensusNet(N, "consensus_byzantine_test", newMockTickerFunc(false), newCounter)
  27. // give the byzantine validator a normal ticker
  28. ticker := NewTimeoutTicker()
  29. ticker.SetLogger(css[0].Logger)
  30. css[0].SetTimeoutTicker(ticker)
  31. switches := make([]*p2p.Switch, N)
  32. p2pLogger := logger.With("module", "p2p")
  33. for i := 0; i < N; i++ {
  34. switches[i] = p2p.NewSwitch(config.P2P)
  35. switches[i].SetLogger(p2pLogger.With("validator", i))
  36. }
  37. eventChans := make([]chan interface{}, N)
  38. reactors := make([]p2p.Reactor, N)
  39. for i := 0; i < N; i++ {
  40. // make first val byzantine
  41. if i == 0 {
  42. // NOTE: Now, test validators are MockPV, which by default doesn't
  43. // do any safety checks.
  44. css[i].privValidator.(*types.MockPV).DisableChecks()
  45. css[i].decideProposal = func(j int) func(int64, int) {
  46. return func(height int64, round int) {
  47. byzantineDecideProposalFunc(t, height, round, css[j], switches[j])
  48. }
  49. }(i)
  50. css[i].doPrevote = func(height int64, round int) {}
  51. }
  52. eventBus := css[i].eventBus
  53. eventBus.SetLogger(logger.With("module", "events", "validator", i))
  54. eventChans[i] = make(chan interface{}, 1)
  55. err := eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i])
  56. require.NoError(t, err)
  57. conR := NewConsensusReactor(css[i], true) // so we dont start the consensus states
  58. conR.SetLogger(logger.With("validator", i))
  59. conR.SetEventBus(eventBus)
  60. var conRI p2p.Reactor // nolint: gotype, gosimple
  61. conRI = conR
  62. // make first val byzantine
  63. if i == 0 {
  64. conRI = NewByzantineReactor(conR)
  65. }
  66. reactors[i] = conRI
  67. }
  68. defer func() {
  69. for _, r := range reactors {
  70. if rr, ok := r.(*ByzantineReactor); ok {
  71. rr.reactor.Switch.Stop()
  72. } else {
  73. r.(*ConsensusReactor).Switch.Stop()
  74. }
  75. }
  76. }()
  77. p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
  78. // ignore new switch s, we already made ours
  79. switches[i].AddReactor("CONSENSUS", reactors[i])
  80. return switches[i]
  81. }, func(sws []*p2p.Switch, i, j int) {
  82. // the network starts partitioned with globally active adversary
  83. if i != 0 {
  84. return
  85. }
  86. p2p.Connect2Switches(sws, i, j)
  87. })
  88. // start the non-byz state machines.
  89. // note these must be started before the byz
  90. for i := 1; i < N; i++ {
  91. cr := reactors[i].(*ConsensusReactor)
  92. cr.SwitchToConsensus(cr.conS.GetState(), 0)
  93. }
  94. // start the byzantine state machine
  95. byzR := reactors[0].(*ByzantineReactor)
  96. s := byzR.reactor.conS.GetState()
  97. byzR.reactor.SwitchToConsensus(s, 0)
  98. // byz proposer sends one block to peers[0]
  99. // and the other block to peers[1] and peers[2].
  100. // note peers and switches order don't match.
  101. peers := switches[0].Peers().List()
  102. // partition A
  103. ind0 := getSwitchIndex(switches, peers[0])
  104. // partition B
  105. ind1 := getSwitchIndex(switches, peers[1])
  106. ind2 := getSwitchIndex(switches, peers[2])
  107. p2p.Connect2Switches(switches, ind1, ind2)
  108. // wait for someone in the big partition (B) to make a block
  109. <-eventChans[ind2]
  110. t.Log("A block has been committed. Healing partition")
  111. p2p.Connect2Switches(switches, ind0, ind1)
  112. p2p.Connect2Switches(switches, ind0, ind2)
  113. // wait till everyone makes the first new block
  114. // (one of them already has)
  115. wg := new(sync.WaitGroup)
  116. wg.Add(2)
  117. for i := 1; i < N-1; i++ {
  118. go func(j int) {
  119. <-eventChans[j]
  120. wg.Done()
  121. }(i)
  122. }
  123. done := make(chan struct{})
  124. go func() {
  125. wg.Wait()
  126. close(done)
  127. }()
  128. tick := time.NewTicker(time.Second * 10)
  129. select {
  130. case <-done:
  131. case <-tick.C:
  132. for i, reactor := range reactors {
  133. t.Log(cmn.Fmt("Consensus Reactor %v", i))
  134. t.Log(cmn.Fmt("%v", reactor))
  135. }
  136. t.Fatalf("Timed out waiting for all validators to commit first block")
  137. }
  138. }
  139. //-------------------------------
  140. // byzantine consensus functions
  141. func byzantineDecideProposalFunc(t *testing.T, height int64, round int, cs *ConsensusState, sw *p2p.Switch) {
  142. // byzantine user should create two proposals and try to split the vote.
  143. // Avoid sending on internalMsgQueue and running consensus state.
  144. // Create a new proposal block from state/txs from the mempool.
  145. block1, blockParts1 := cs.createProposalBlock()
  146. polRound, polBlockID := cs.Votes.POLInfo()
  147. proposal1 := types.NewProposal(height, round, blockParts1.Header(), polRound, polBlockID)
  148. if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal1); err != nil {
  149. t.Error(err)
  150. }
  151. // Create a new proposal block from state/txs from the mempool.
  152. block2, blockParts2 := cs.createProposalBlock()
  153. polRound, polBlockID = cs.Votes.POLInfo()
  154. proposal2 := types.NewProposal(height, round, blockParts2.Header(), polRound, polBlockID)
  155. if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal2); err != nil {
  156. t.Error(err)
  157. }
  158. block1Hash := block1.Hash()
  159. block2Hash := block2.Hash()
  160. // broadcast conflicting proposals/block parts to peers
  161. peers := sw.Peers().List()
  162. t.Logf("Byzantine: broadcasting conflicting proposals to %d peers", len(peers))
  163. for i, peer := range peers {
  164. if i < len(peers)/2 {
  165. go sendProposalAndParts(height, round, cs, peer, proposal1, block1Hash, blockParts1)
  166. } else {
  167. go sendProposalAndParts(height, round, cs, peer, proposal2, block2Hash, blockParts2)
  168. }
  169. }
  170. }
  171. func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.Peer, proposal *types.Proposal, blockHash []byte, parts *types.PartSet) {
  172. // proposal
  173. msg := &ProposalMessage{Proposal: proposal}
  174. peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
  175. // parts
  176. for i := 0; i < parts.Total(); i++ {
  177. part := parts.GetPart(i)
  178. msg := &BlockPartMessage{
  179. Height: height, // This tells peer that this part applies to us.
  180. Round: round, // This tells peer that this part applies to us.
  181. Part: part,
  182. }
  183. peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
  184. }
  185. // votes
  186. cs.mtx.Lock()
  187. prevote, _ := cs.signVote(types.VoteTypePrevote, blockHash, parts.Header())
  188. precommit, _ := cs.signVote(types.VoteTypePrecommit, blockHash, parts.Header())
  189. cs.mtx.Unlock()
  190. peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{prevote}))
  191. peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{precommit}))
  192. }
  193. //----------------------------------------
  194. // byzantine consensus reactor
  195. type ByzantineReactor struct {
  196. cmn.Service
  197. reactor *ConsensusReactor
  198. }
  199. func NewByzantineReactor(conR *ConsensusReactor) *ByzantineReactor {
  200. return &ByzantineReactor{
  201. Service: conR,
  202. reactor: conR,
  203. }
  204. }
  205. func (br *ByzantineReactor) SetSwitch(s *p2p.Switch) { br.reactor.SetSwitch(s) }
  206. func (br *ByzantineReactor) GetChannels() []*p2p.ChannelDescriptor { return br.reactor.GetChannels() }
  207. func (br *ByzantineReactor) AddPeer(peer p2p.Peer) {
  208. if !br.reactor.IsRunning() {
  209. return
  210. }
  211. // Create peerState for peer
  212. peerState := NewPeerState(peer).SetLogger(br.reactor.Logger)
  213. peer.Set(types.PeerStateKey, peerState)
  214. // Send our state to peer.
  215. // If we're fast_syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
  216. if !br.reactor.fastSync {
  217. br.reactor.sendNewRoundStepMessages(peer)
  218. }
  219. }
  220. func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
  221. br.reactor.RemovePeer(peer, reason)
  222. }
  223. func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
  224. br.reactor.Receive(chID, peer, msgBytes)
  225. }