github.com/devwanda/aphelion-staking@v0.33.9/consensus/invalid_test.go (about)

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