github.com/arcology-network/consensus-engine@v1.9.0/consensus/invalid_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/arcology-network/consensus-engine/libs/bytes"
     7  	"github.com/arcology-network/consensus-engine/libs/log"
     8  	tmrand "github.com/arcology-network/consensus-engine/libs/rand"
     9  	"github.com/arcology-network/consensus-engine/p2p"
    10  	tmproto "github.com/arcology-network/consensus-engine/proto/tendermint/types"
    11  	"github.com/arcology-network/consensus-engine/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  }