|
|
@ -87,10 +87,12 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { |
|
|
|
mempool.EnableTxsAvailable() |
|
|
|
} |
|
|
|
|
|
|
|
eventBus := eventbus.NewDefault(log.TestingLogger().With("module", "events")) |
|
|
|
require.NoError(t, eventBus.Start(ctx)) |
|
|
|
|
|
|
|
// Make a full instance of the evidence pool
|
|
|
|
evidenceDB := dbm.NewMemDB() |
|
|
|
evpool, err := evidence.NewPool(logger.With("module", "evidence"), evidenceDB, stateStore, blockStore, evidence.NopMetrics()) |
|
|
|
require.NoError(t, err) |
|
|
|
evpool := evidence.NewPool(logger.With("module", "evidence"), evidenceDB, stateStore, blockStore, evidence.NopMetrics(), eventBus) |
|
|
|
|
|
|
|
// Make State
|
|
|
|
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool, blockStore) |
|
|
@ -100,11 +102,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { |
|
|
|
pv := privVals[i] |
|
|
|
cs.SetPrivValidator(ctx, pv) |
|
|
|
|
|
|
|
eventBus := eventbus.NewDefault(log.TestingLogger().With("module", "events")) |
|
|
|
err = eventBus.Start(ctx) |
|
|
|
require.NoError(t, err) |
|
|
|
cs.SetEventBus(eventBus) |
|
|
|
evpool.SetEventBus(eventBus) |
|
|
|
cs.SetTimeoutTicker(tickerFunc()) |
|
|
|
|
|
|
|
states[i] = cs |
|
|
@ -327,42 +325,42 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) { |
|
|
|
// blocksSubs := make([]types.Subscription, n)
|
|
|
|
// reactors := make([]p2p.Reactor, n)
|
|
|
|
// for i := 0; i < n; i++ {
|
|
|
|
// // enable txs so we can create different proposals
|
|
|
|
// assertMempool(states[i].txNotifier).EnableTxsAvailable()
|
|
|
|
// // enable txs so we can create different proposals
|
|
|
|
// assertMempool(states[i].txNotifier).EnableTxsAvailable()
|
|
|
|
|
|
|
|
// eventBus := states[i].eventBus
|
|
|
|
// eventBus.SetLogger(logger.With("module", "events", "validator", i))
|
|
|
|
// eventBus := states[i].eventBus
|
|
|
|
// eventBus.SetLogger(logger.With("module", "events", "validator", i))
|
|
|
|
|
|
|
|
// var err error
|
|
|
|
// blocksSubs[i], err = eventBus.Subscribe(ctx, testSubscriber, types.EventQueryNewBlock)
|
|
|
|
// require.NoError(t, err)
|
|
|
|
// var err error
|
|
|
|
// blocksSubs[i], err = eventBus.Subscribe(ctx, testSubscriber, types.EventQueryNewBlock)
|
|
|
|
// require.NoError(t, err)
|
|
|
|
|
|
|
|
// conR := NewReactor(states[i], true) // so we don't start the consensus states
|
|
|
|
// conR.SetLogger(logger.With("validator", i))
|
|
|
|
// conR.SetEventBus(eventBus)
|
|
|
|
// conR := NewReactor(states[i], true) // so we don't start the consensus states
|
|
|
|
// conR.SetLogger(logger.With("validator", i))
|
|
|
|
// conR.SetEventBus(eventBus)
|
|
|
|
|
|
|
|
// var conRI p2p.Reactor = conR
|
|
|
|
// var conRI p2p.Reactor = conR
|
|
|
|
|
|
|
|
// // make first val byzantine
|
|
|
|
// if i == 0 {
|
|
|
|
// conRI = NewByzantineReactor(conR)
|
|
|
|
// }
|
|
|
|
// // make first val byzantine
|
|
|
|
// if i == 0 {
|
|
|
|
// conRI = NewByzantineReactor(conR)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// reactors[i] = conRI
|
|
|
|
// err = states[i].blockExec.Store().Save(states[i].state) // for save height 1's validators info
|
|
|
|
// require.NoError(t, err)
|
|
|
|
// reactors[i] = conRI
|
|
|
|
// err = states[i].blockExec.Store().Save(states[i].state) // for save height 1's validators info
|
|
|
|
// require.NoError(t, err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// switches := p2p.MakeConnectedSwitches(config.P2P, N, func(i int, sw *p2p.Switch) *p2p.Switch {
|
|
|
|
// sw.SetLogger(p2pLogger.With("validator", i))
|
|
|
|
// sw.AddReactor("CONSENSUS", reactors[i])
|
|
|
|
// return sw
|
|
|
|
// sw.SetLogger(p2pLogger.With("validator", i))
|
|
|
|
// sw.AddReactor("CONSENSUS", reactors[i])
|
|
|
|
// return sw
|
|
|
|
// }, func(sws []*p2p.Switch, i, j int) {
|
|
|
|
// // the network starts partitioned with globally active adversary
|
|
|
|
// if i != 0 {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
// p2p.Connect2Switches(sws, i, j)
|
|
|
|
// // the network starts partitioned with globally active adversary
|
|
|
|
// if i != 0 {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
// p2p.Connect2Switches(sws, i, j)
|
|
|
|
// })
|
|
|
|
|
|
|
|
// // make first val byzantine
|
|
|
@ -370,26 +368,26 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) { |
|
|
|
// // do any safety checks.
|
|
|
|
// states[0].privValidator.(types.MockPV).DisableChecks()
|
|
|
|
// states[0].decideProposal = func(j int32) func(int64, int32) {
|
|
|
|
// return func(height int64, round int32) {
|
|
|
|
// byzantineDecideProposalFunc(t, height, round, states[j], switches[j])
|
|
|
|
// }
|
|
|
|
// return func(height int64, round int32) {
|
|
|
|
// byzantineDecideProposalFunc(t, height, round, states[j], switches[j])
|
|
|
|
// }
|
|
|
|
// }(int32(0))
|
|
|
|
// // We are setting the prevote function to do nothing because the prevoting
|
|
|
|
// // and precommitting are done alongside the proposal.
|
|
|
|
// states[0].doPrevote = func(height int64, round int32) {}
|
|
|
|
|
|
|
|
// defer func() {
|
|
|
|
// for _, sw := range switches {
|
|
|
|
// err := sw.Stop()
|
|
|
|
// require.NoError(t, err)
|
|
|
|
// }
|
|
|
|
// for _, sw := range switches {
|
|
|
|
// err := sw.Stop()
|
|
|
|
// require.NoError(t, err)
|
|
|
|
// }
|
|
|
|
// }()
|
|
|
|
|
|
|
|
// // start the non-byz state machines.
|
|
|
|
// // note these must be started before the byz
|
|
|
|
// for i := 1; i < n; i++ {
|
|
|
|
// cr := reactors[i].(*Reactor)
|
|
|
|
// cr.SwitchToConsensus(cr.conS.GetState(), false)
|
|
|
|
// cr := reactors[i].(*Reactor)
|
|
|
|
// cr.SwitchToConsensus(cr.conS.GetState(), false)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // start the byzantine state machine
|
|
|
@ -421,146 +419,146 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) { |
|
|
|
// // (one of them already has)
|
|
|
|
// wg := new(sync.WaitGroup)
|
|
|
|
// for i := 1; i < N-1; i++ {
|
|
|
|
// wg.Add(1)
|
|
|
|
// go func(j int) {
|
|
|
|
// <-blocksSubs[j].Out()
|
|
|
|
// wg.Done()
|
|
|
|
// }(i)
|
|
|
|
// wg.Add(1)
|
|
|
|
// go func(j int) {
|
|
|
|
// <-blocksSubs[j].Out()
|
|
|
|
// wg.Done()
|
|
|
|
// }(i)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// done := make(chan struct{})
|
|
|
|
// go func() {
|
|
|
|
// wg.Wait()
|
|
|
|
// close(done)
|
|
|
|
// wg.Wait()
|
|
|
|
// close(done)
|
|
|
|
// }()
|
|
|
|
|
|
|
|
// tick := time.NewTicker(time.Second * 10)
|
|
|
|
// select {
|
|
|
|
// case <-done:
|
|
|
|
// case <-tick.C:
|
|
|
|
// for i, reactor := range reactors {
|
|
|
|
// t.Log(fmt.Sprintf("Consensus Reactor %v", i))
|
|
|
|
// t.Log(fmt.Sprintf("%v", reactor))
|
|
|
|
// }
|
|
|
|
// t.Fatalf("Timed out waiting for all validators to commit first block")
|
|
|
|
// for i, reactor := range reactors {
|
|
|
|
// t.Log(fmt.Sprintf("Consensus Reactor %v", i))
|
|
|
|
// t.Log(fmt.Sprintf("%v", reactor))
|
|
|
|
// }
|
|
|
|
// t.Fatalf("Timed out waiting for all validators to commit first block")
|
|
|
|
// }
|
|
|
|
} |
|
|
|
|
|
|
|
// func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *State, sw *p2p.Switch) {
|
|
|
|
// // byzantine user should create two proposals and try to split the vote.
|
|
|
|
// // Avoid sending on internalMsgQueue and running consensus state.
|
|
|
|
|
|
|
|
// // Create a new proposal block from state/txs from the mempool.
|
|
|
|
// block1, blockParts1 := cs.createProposalBlock()
|
|
|
|
// polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()}
|
|
|
|
// proposal1 := types.NewProposal(height, round, polRound, propBlockID)
|
|
|
|
// p1 := proposal1.ToProto()
|
|
|
|
// if err := cs.privValidator.SignProposal(cs.state.ChainID, p1); err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// proposal1.Signature = p1.Signature
|
|
|
|
|
|
|
|
// // some new transactions come in (this ensures that the proposals are different)
|
|
|
|
// deliverTxsRange(cs, 0, 1)
|
|
|
|
|
|
|
|
// // Create a new proposal block from state/txs from the mempool.
|
|
|
|
// block2, blockParts2 := cs.createProposalBlock()
|
|
|
|
// polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()}
|
|
|
|
// proposal2 := types.NewProposal(height, round, polRound, propBlockID)
|
|
|
|
// p2 := proposal2.ToProto()
|
|
|
|
// if err := cs.privValidator.SignProposal(cs.state.ChainID, p2); err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// proposal2.Signature = p2.Signature
|
|
|
|
|
|
|
|
// block1Hash := block1.Hash()
|
|
|
|
// block2Hash := block2.Hash()
|
|
|
|
|
|
|
|
// // broadcast conflicting proposals/block parts to peers
|
|
|
|
// peers := sw.Peers().List()
|
|
|
|
// t.Logf("Byzantine: broadcasting conflicting proposals to %d peers", len(peers))
|
|
|
|
// for i, peer := range peers {
|
|
|
|
// if i < len(peers)/2 {
|
|
|
|
// go sendProposalAndParts(height, round, cs, peer, proposal1, block1Hash, blockParts1)
|
|
|
|
// } else {
|
|
|
|
// go sendProposalAndParts(height, round, cs, peer, proposal2, block2Hash, blockParts2)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// // byzantine user should create two proposals and try to split the vote.
|
|
|
|
// // Avoid sending on internalMsgQueue and running consensus state.
|
|
|
|
|
|
|
|
// // Create a new proposal block from state/txs from the mempool.
|
|
|
|
// block1, blockParts1 := cs.createProposalBlock()
|
|
|
|
// polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()}
|
|
|
|
// proposal1 := types.NewProposal(height, round, polRound, propBlockID)
|
|
|
|
// p1 := proposal1.ToProto()
|
|
|
|
// if err := cs.privValidator.SignProposal(cs.state.ChainID, p1); err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// proposal1.Signature = p1.Signature
|
|
|
|
|
|
|
|
// // some new transactions come in (this ensures that the proposals are different)
|
|
|
|
// deliverTxsRange(cs, 0, 1)
|
|
|
|
|
|
|
|
// // Create a new proposal block from state/txs from the mempool.
|
|
|
|
// block2, blockParts2 := cs.createProposalBlock()
|
|
|
|
// polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()}
|
|
|
|
// proposal2 := types.NewProposal(height, round, polRound, propBlockID)
|
|
|
|
// p2 := proposal2.ToProto()
|
|
|
|
// if err := cs.privValidator.SignProposal(cs.state.ChainID, p2); err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// proposal2.Signature = p2.Signature
|
|
|
|
|
|
|
|
// block1Hash := block1.Hash()
|
|
|
|
// block2Hash := block2.Hash()
|
|
|
|
|
|
|
|
// // broadcast conflicting proposals/block parts to peers
|
|
|
|
// peers := sw.Peers().List()
|
|
|
|
// t.Logf("Byzantine: broadcasting conflicting proposals to %d peers", len(peers))
|
|
|
|
// for i, peer := range peers {
|
|
|
|
// if i < len(peers)/2 {
|
|
|
|
// go sendProposalAndParts(height, round, cs, peer, proposal1, block1Hash, blockParts1)
|
|
|
|
// } else {
|
|
|
|
// go sendProposalAndParts(height, round, cs, peer, proposal2, block2Hash, blockParts2)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func sendProposalAndParts(
|
|
|
|
// height int64,
|
|
|
|
// round int32,
|
|
|
|
// cs *State,
|
|
|
|
// peer p2p.Peer,
|
|
|
|
// proposal *types.Proposal,
|
|
|
|
// blockHash []byte,
|
|
|
|
// parts *types.PartSet,
|
|
|
|
// height int64,
|
|
|
|
// round int32,
|
|
|
|
// cs *State,
|
|
|
|
// peer p2p.Peer,
|
|
|
|
// proposal *types.Proposal,
|
|
|
|
// blockHash []byte,
|
|
|
|
// parts *types.PartSet,
|
|
|
|
// ) {
|
|
|
|
// // proposal
|
|
|
|
// msg := &ProposalMessage{Proposal: proposal}
|
|
|
|
// peer.Send(DataChannel, MustEncode(msg))
|
|
|
|
|
|
|
|
// // parts
|
|
|
|
// for i := 0; i < int(parts.Total()); i++ {
|
|
|
|
// part := parts.GetPart(i)
|
|
|
|
// msg := &BlockPartMessage{
|
|
|
|
// Height: height, // This tells peer that this part applies to us.
|
|
|
|
// Round: round, // This tells peer that this part applies to us.
|
|
|
|
// Part: part,
|
|
|
|
// }
|
|
|
|
// peer.Send(DataChannel, MustEncode(msg))
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // votes
|
|
|
|
// cs.mtx.Lock()
|
|
|
|
// prevote, _ := cs.signVote(tmproto.PrevoteType, blockHash, parts.Header())
|
|
|
|
// precommit, _ := cs.signVote(tmproto.PrecommitType, blockHash, parts.Header())
|
|
|
|
// cs.mtx.Unlock()
|
|
|
|
|
|
|
|
// peer.Send(VoteChannel, MustEncode(&VoteMessage{prevote}))
|
|
|
|
// peer.Send(VoteChannel, MustEncode(&VoteMessage{precommit}))
|
|
|
|
// // proposal
|
|
|
|
// msg := &ProposalMessage{Proposal: proposal}
|
|
|
|
// peer.Send(DataChannel, MustEncode(msg))
|
|
|
|
|
|
|
|
// // parts
|
|
|
|
// for i := 0; i < int(parts.Total()); i++ {
|
|
|
|
// part := parts.GetPart(i)
|
|
|
|
// msg := &BlockPartMessage{
|
|
|
|
// Height: height, // This tells peer that this part applies to us.
|
|
|
|
// Round: round, // This tells peer that this part applies to us.
|
|
|
|
// Part: part,
|
|
|
|
// }
|
|
|
|
// peer.Send(DataChannel, MustEncode(msg))
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // votes
|
|
|
|
// cs.mtx.Lock()
|
|
|
|
// prevote, _ := cs.signVote(tmproto.PrevoteType, blockHash, parts.Header())
|
|
|
|
// precommit, _ := cs.signVote(tmproto.PrecommitType, blockHash, parts.Header())
|
|
|
|
// cs.mtx.Unlock()
|
|
|
|
|
|
|
|
// peer.Send(VoteChannel, MustEncode(&VoteMessage{prevote}))
|
|
|
|
// peer.Send(VoteChannel, MustEncode(&VoteMessage{precommit}))
|
|
|
|
// }
|
|
|
|
|
|
|
|
// type ByzantineReactor struct {
|
|
|
|
// service.Service
|
|
|
|
// reactor *Reactor
|
|
|
|
// service.Service
|
|
|
|
// reactor *Reactor
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func NewByzantineReactor(conR *Reactor) *ByzantineReactor {
|
|
|
|
// return &ByzantineReactor{
|
|
|
|
// Service: conR,
|
|
|
|
// reactor: conR,
|
|
|
|
// }
|
|
|
|
// return &ByzantineReactor{
|
|
|
|
// Service: conR,
|
|
|
|
// reactor: conR,
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func (br *ByzantineReactor) SetSwitch(s *p2p.Switch) { br.reactor.SetSwitch(s) }
|
|
|
|
// func (br *ByzantineReactor) GetChannels() []*p2p.ChannelDescriptor { return br.reactor.GetChannels() }
|
|
|
|
|
|
|
|
// func (br *ByzantineReactor) AddPeer(peer p2p.Peer) {
|
|
|
|
// if !br.reactor.IsRunning() {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // Create peerState for peer
|
|
|
|
// peerState := NewPeerState(peer).SetLogger(br.reactor.logger)
|
|
|
|
// peer.Set(types.PeerStateKey, peerState)
|
|
|
|
|
|
|
|
// // Send our state to peer.
|
|
|
|
// // If we're syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
|
|
|
|
// if !br.reactor.waitSync {
|
|
|
|
// br.reactor.sendNewRoundStepMessage(peer)
|
|
|
|
// }
|
|
|
|
// if !br.reactor.IsRunning() {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // Create peerState for peer
|
|
|
|
// peerState := NewPeerState(peer).SetLogger(br.reactor.logger)
|
|
|
|
// peer.Set(types.PeerStateKey, peerState)
|
|
|
|
|
|
|
|
// // Send our state to peer.
|
|
|
|
// // If we're syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
|
|
|
|
// if !br.reactor.waitSync {
|
|
|
|
// br.reactor.sendNewRoundStepMessage(peer)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
|
|
|
// br.reactor.RemovePeer(peer, reason)
|
|
|
|
// br.reactor.RemovePeer(peer, reason)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
|
|
|
|
// br.reactor.Receive(chID, peer, msgBytes)
|
|
|
|
// br.reactor.Receive(chID, peer, msgBytes)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func (br *ByzantineReactor) InitPeer(peer p2p.Peer) p2p.Peer { return peer }
|