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.

284 lines
8.5 KiB

  1. package consensus
  2. import (
  3. "fmt"
  4. "net"
  5. "sync"
  6. "testing"
  7. "time"
  8. "github.com/tendermint/tendermint/config/tendermint_test"
  9. "github.com/tendermint/ed25519"
  10. . "github.com/tendermint/go-common"
  11. cfg "github.com/tendermint/go-config"
  12. "github.com/tendermint/go-crypto"
  13. dbm "github.com/tendermint/go-db"
  14. "github.com/tendermint/go-events"
  15. "github.com/tendermint/go-p2p"
  16. bc "github.com/tendermint/tendermint/blockchain"
  17. "github.com/tendermint/tendermint/types"
  18. )
  19. func init() {
  20. config = tendermint_test.ResetConfig("consensus_reactor_test")
  21. }
  22. func resetConfigTimeouts() {
  23. config.Set("log_level", "notice")
  24. config.Set("timeout_propose", 2000)
  25. // config.Set("timeout_propose_delta", 500)
  26. // config.Set("timeout_prevote", 1000)
  27. // config.Set("timeout_prevote_delta", 500)
  28. // config.Set("timeout_precommit", 1000)
  29. // config.Set("timeout_precommit_delta", 500)
  30. // config.Set("timeout_commit", 1000)
  31. }
  32. func TestReactor(t *testing.T) {
  33. resetConfigTimeouts()
  34. N := 4
  35. css := randConsensusNet(N)
  36. reactors := make([]*ConsensusReactor, N)
  37. eventChans := make([]chan interface{}, N)
  38. for i := 0; i < N; i++ {
  39. blockStoreDB := dbm.NewDB(Fmt("blockstore%d", i), config.GetString("db_backend"), config.GetString("db_dir"))
  40. blockStore := bc.NewBlockStore(blockStoreDB)
  41. reactors[i] = NewConsensusReactor(css[i], blockStore, false)
  42. reactors[i].SetPrivValidator(css[i].privValidator)
  43. eventSwitch := events.NewEventSwitch()
  44. _, err := eventSwitch.Start()
  45. if err != nil {
  46. t.Fatalf("Failed to start switch: %v", err)
  47. }
  48. reactors[i].SetEventSwitch(eventSwitch)
  49. eventChans[i] = subscribeToEvent(eventSwitch, "tester", types.EventStringNewBlock(), 1)
  50. }
  51. p2p.MakeConnectedSwitches(N, func(i int, s *p2p.Switch) *p2p.Switch {
  52. s.AddReactor("CONSENSUS", reactors[i])
  53. return s
  54. }, net.Pipe)
  55. // wait till everyone makes the first new block
  56. wg := new(sync.WaitGroup)
  57. wg.Add(N)
  58. for i := 0; i < N; i++ {
  59. go func(j int) {
  60. <-eventChans[j]
  61. wg.Done()
  62. }(i)
  63. }
  64. done := make(chan struct{})
  65. go func() {
  66. wg.Wait()
  67. close(done)
  68. }()
  69. tick := time.NewTicker(time.Second * 3)
  70. select {
  71. case <-done:
  72. case <-tick.C:
  73. t.Fatalf("Timed out waiting for all validators to commit first block")
  74. }
  75. }
  76. func TestByzantine(t *testing.T) {
  77. resetConfigTimeouts()
  78. N := 4
  79. css := randConsensusNet(N)
  80. switches := make([]*p2p.Switch, N)
  81. for i := 0; i < N; i++ {
  82. switches[i] = p2p.NewSwitch(cfg.NewMapConfig(nil))
  83. }
  84. reactors := make([]*ConsensusReactor, N)
  85. eventChans := make([]chan interface{}, N)
  86. for i := 0; i < N; i++ {
  87. blockStoreDB := dbm.NewDB(Fmt("blockstore%d", i), config.GetString("db_backend"), config.GetString("db_dir"))
  88. blockStore := bc.NewBlockStore(blockStoreDB)
  89. if i == 0 {
  90. // make byzantine
  91. css[i].decideProposal = func(j int) func(int, int) {
  92. return func(height, round int) {
  93. fmt.Println("hmph", j)
  94. byzantineDecideProposalFunc(height, round, css[j], switches[j])
  95. }
  96. }(i)
  97. css[i].doPrevote = func(height, round int) {}
  98. css[i].setProposal = func(j int) func(proposal *types.Proposal) error {
  99. return func(proposal *types.Proposal) error {
  100. return byzantineSetProposal(proposal, css[j], switches[j])
  101. }
  102. }(i)
  103. }
  104. reactors[i] = NewConsensusReactor(css[i], blockStore, false)
  105. reactors[i].SetPrivValidator(css[i].privValidator)
  106. eventSwitch := events.NewEventSwitch()
  107. _, err := eventSwitch.Start()
  108. if err != nil {
  109. t.Fatalf("Failed to start switch: %v", err)
  110. }
  111. reactors[i].SetEventSwitch(eventSwitch)
  112. eventChans[i] = subscribeToEvent(eventSwitch, "tester", types.EventStringNewBlock(), 1)
  113. }
  114. p2p.MakeConnectedSwitches(N, func(i int, s *p2p.Switch) *p2p.Switch {
  115. s.AddReactor("CONSENSUS", reactors[i])
  116. return s
  117. }, net.Pipe)
  118. // wait till everyone makes the first new block
  119. wg := new(sync.WaitGroup)
  120. wg.Add(N)
  121. for i := 0; i < N; i++ {
  122. go func(j int) {
  123. <-eventChans[j]
  124. wg.Done()
  125. }(i)
  126. }
  127. done := make(chan struct{})
  128. go func() {
  129. wg.Wait()
  130. close(done)
  131. }()
  132. tick := time.NewTicker(time.Second * 3)
  133. select {
  134. case <-done:
  135. case <-tick.C:
  136. t.Fatalf("Timed out waiting for all validators to commit first block")
  137. }
  138. }
  139. //-------------------------------
  140. // byzantine consensus functions
  141. func byzantineDecideProposalFunc(height, 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. cs.privValidator.SignProposal(cs.state.ChainID, proposal1) // byzantine doesnt err
  149. // Create a new proposal block from state/txs from the mempool.
  150. block2, blockParts2 := cs.createProposalBlock()
  151. polRound, polBlockID = cs.Votes.POLInfo()
  152. proposal2 := types.NewProposal(height, round, blockParts2.Header(), polRound, polBlockID)
  153. cs.privValidator.SignProposal(cs.state.ChainID, proposal2) // byzantine doesnt err
  154. log.Notice("Byzantine: broadcasting conflicting proposals")
  155. // broadcast conflicting proposals/block parts to peers
  156. peers := sw.Peers().List()
  157. for i, peer := range peers {
  158. if i < len(peers)/2 {
  159. go sendProposalAndParts(height, round, cs, peer, proposal1, block1, blockParts1)
  160. } else {
  161. go sendProposalAndParts(height, round, cs, peer, proposal2, block2, blockParts2)
  162. }
  163. }
  164. }
  165. func sendProposalAndParts(height, round int, cs *ConsensusState, peer *p2p.Peer, proposal *types.Proposal, block *types.Block, parts *types.PartSet) {
  166. // proposal
  167. msg := &ProposalMessage{Proposal: proposal}
  168. peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
  169. // parts
  170. for i := 0; i < parts.Total(); i++ {
  171. part := parts.GetPart(i)
  172. msg := &BlockPartMessage{
  173. Height: height, // This tells peer that this part applies to us.
  174. Round: round, // This tells peer that this part applies to us.
  175. Part: part,
  176. }
  177. peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
  178. }
  179. // votes
  180. prevote, _ := cs.signVote(types.VoteTypePrevote, block.Hash(), parts.Header())
  181. peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{prevote}})
  182. precommit, _ := cs.signVote(types.VoteTypePrecommit, block.Hash(), parts.Header())
  183. peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{precommit}})
  184. }
  185. func byzantineSetProposal(proposal *types.Proposal, cs *ConsensusState, sw *p2p.Switch) error {
  186. peers := sw.Peers().List()
  187. for _, peer := range peers {
  188. // votes
  189. var blockHash []byte // XXX proposal.BlockHash
  190. blockHash = []byte{0, 1, 0, 2, 0, 3}
  191. prevote, _ := cs.signVote(types.VoteTypePrevote, blockHash, proposal.BlockPartsHeader)
  192. peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{prevote}})
  193. precommit, _ := cs.signVote(types.VoteTypePrecommit, blockHash, proposal.BlockPartsHeader)
  194. peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{precommit}})
  195. }
  196. return nil
  197. }
  198. //----------------------------------------
  199. // byzantine privValidator
  200. type ByzantinePrivValidator struct {
  201. Address []byte `json:"address"`
  202. PubKey crypto.PubKey `json:"pub_key"`
  203. // PrivKey should be empty if a Signer other than the default is being used.
  204. PrivKey crypto.PrivKey `json:"priv_key"`
  205. types.Signer `json:"-"`
  206. mtx sync.Mutex
  207. }
  208. func (privVal *ByzantinePrivValidator) SetSigner(s types.Signer) {
  209. privVal.Signer = s
  210. }
  211. // Generates a new validator with private key.
  212. func GenPrivValidator() *ByzantinePrivValidator {
  213. privKeyBytes := new([64]byte)
  214. copy(privKeyBytes[:32], crypto.CRandBytes(32))
  215. pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
  216. pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
  217. privKey := crypto.PrivKeyEd25519(*privKeyBytes)
  218. return &ByzantinePrivValidator{
  219. Address: pubKey.Address(),
  220. PubKey: pubKey,
  221. PrivKey: privKey,
  222. Signer: types.NewDefaultSigner(privKey),
  223. }
  224. }
  225. func (privVal *ByzantinePrivValidator) GetAddress() []byte {
  226. return privVal.Address
  227. }
  228. func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) error {
  229. privVal.mtx.Lock()
  230. defer privVal.mtx.Unlock()
  231. // Sign
  232. vote.Signature = privVal.Sign(types.SignBytes(chainID, vote)).(crypto.SignatureEd25519)
  233. return nil
  234. }
  235. func (privVal *ByzantinePrivValidator) SignProposal(chainID string, proposal *types.Proposal) error {
  236. privVal.mtx.Lock()
  237. defer privVal.mtx.Unlock()
  238. // Sign
  239. proposal.Signature = privVal.Sign(types.SignBytes(chainID, proposal)).(crypto.SignatureEd25519)
  240. return nil
  241. }
  242. func (privVal *ByzantinePrivValidator) String() string {
  243. return Fmt("PrivValidator{%X}", privVal.Address)
  244. }