github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/rpc/client/evidence_test.go (about)

     1  package client_test
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	abci "github.com/tendermint/tendermint/abci/types"
    12  	"github.com/tendermint/tendermint/crypto"
    13  	"github.com/tendermint/tendermint/crypto/ed25519"
    14  	cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
    15  	"github.com/tendermint/tendermint/crypto/tmhash"
    16  	"github.com/tendermint/tendermint/privval"
    17  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    18  	"github.com/tendermint/tendermint/rpc/client"
    19  	rpctest "github.com/tendermint/tendermint/rpc/test"
    20  	"github.com/tendermint/tendermint/types"
    21  )
    22  
    23  func newEvidence(t *testing.T, val *privval.FilePV,
    24  	vote *types.Vote, vote2 *types.Vote,
    25  	chainID string) *types.DuplicateVoteEvidence {
    26  
    27  	var err error
    28  
    29  	v := vote.ToProto()
    30  	v2 := vote2.ToProto()
    31  
    32  	vote.Signature, err = val.Key.PrivKey.Sign(types.VoteSignBytes(chainID, v))
    33  	require.NoError(t, err)
    34  
    35  	vote2.Signature, err = val.Key.PrivKey.Sign(types.VoteSignBytes(chainID, v2))
    36  	require.NoError(t, err)
    37  
    38  	return types.NewDuplicateVoteEvidence(vote, vote2)
    39  }
    40  
    41  func makeEvidences(
    42  	t *testing.T,
    43  	val *privval.FilePV,
    44  	chainID string,
    45  ) (correct *types.DuplicateVoteEvidence, fakes []*types.DuplicateVoteEvidence) {
    46  	vote := types.Vote{
    47  		ValidatorAddress: val.Key.Address,
    48  		ValidatorIndex:   0,
    49  		Height:           1,
    50  		Round:            0,
    51  		Type:             tmproto.PrevoteType,
    52  		Timestamp:        time.Now().UTC(),
    53  		BlockID: types.BlockID{
    54  			Hash: tmhash.Sum([]byte("blockhash")),
    55  			PartSetHeader: types.PartSetHeader{
    56  				Total: 1000,
    57  				Hash:  tmhash.Sum([]byte("partset")),
    58  			},
    59  		},
    60  	}
    61  
    62  	vote2 := vote
    63  	vote2.BlockID.Hash = tmhash.Sum([]byte("blockhash2"))
    64  	correct = newEvidence(t, val, &vote, &vote2, chainID)
    65  
    66  	fakes = make([]*types.DuplicateVoteEvidence, 0)
    67  
    68  	// different address
    69  	{
    70  		v := vote2
    71  		v.ValidatorAddress = []byte("some_address")
    72  		fakes = append(fakes, newEvidence(t, val, &vote, &v, chainID))
    73  	}
    74  
    75  	// different index
    76  	{
    77  		v := vote2
    78  		v.ValidatorIndex = vote.ValidatorIndex + 1
    79  		fakes = append(fakes, newEvidence(t, val, &vote, &v, chainID))
    80  	}
    81  
    82  	// different height
    83  	{
    84  		v := vote2
    85  		v.Height = vote.Height + 1
    86  		fakes = append(fakes, newEvidence(t, val, &vote, &v, chainID))
    87  	}
    88  
    89  	// different round
    90  	{
    91  		v := vote2
    92  		v.Round = vote.Round + 1
    93  		fakes = append(fakes, newEvidence(t, val, &vote, &v, chainID))
    94  	}
    95  
    96  	// different type
    97  	{
    98  		v := vote2
    99  		v.Type = tmproto.PrecommitType
   100  		fakes = append(fakes, newEvidence(t, val, &vote, &v, chainID))
   101  	}
   102  
   103  	// exactly same vote
   104  	{
   105  		v := vote
   106  		fakes = append(fakes, newEvidence(t, val, &vote, &v, chainID))
   107  	}
   108  
   109  	return correct, fakes
   110  }
   111  
   112  func TestBroadcastEvidence_DuplicateVoteEvidence(t *testing.T) {
   113  	var (
   114  		config  = rpctest.GetConfig()
   115  		chainID = config.ChainID()
   116  		pv      = privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
   117  	)
   118  
   119  	correct, fakes := makeEvidences(t, pv, chainID)
   120  
   121  	for i, c := range GetClients() {
   122  		t.Logf("client %d", i)
   123  
   124  		result, err := c.BroadcastEvidence(correct)
   125  		require.NoError(t, err, "BroadcastEvidence(%s) failed", correct)
   126  		assert.Equal(t, correct.Hash(), result.Hash, "expected result hash to match evidence hash")
   127  
   128  		status, err := c.Status()
   129  		require.NoError(t, err)
   130  		err = client.WaitForHeight(c, status.SyncInfo.LatestBlockHeight+2, nil)
   131  		require.NoError(t, err)
   132  
   133  		ed25519pub := pv.Key.PubKey.(ed25519.PubKey)
   134  		rawpub := ed25519pub.Bytes()
   135  		result2, err := c.ABCIQuery("/val", rawpub)
   136  		require.NoError(t, err)
   137  		qres := result2.Response
   138  		require.True(t, qres.IsOK())
   139  
   140  		var v abci.ValidatorUpdate
   141  		err = abci.ReadMessage(bytes.NewReader(qres.Value), &v)
   142  		require.NoError(t, err, "Error reading query result, value %v", qres.Value)
   143  
   144  		pk, err := cryptoenc.PubKeyFromProto(v.PubKey)
   145  		require.NoError(t, err)
   146  
   147  		require.EqualValues(t, rawpub, pk.Bytes(), "Stored PubKey not equal with expected, value %v", string(qres.Value))
   148  		require.Equal(t, int64(9), v.Power, "Stored Power not equal with expected, value %v", string(qres.Value))
   149  
   150  		for _, fake := range fakes {
   151  			_, err := c.BroadcastEvidence(fake)
   152  			require.Error(t, err, "BroadcastEvidence(%s) succeeded, but the evidence was fake", fake)
   153  		}
   154  	}
   155  }
   156  
   157  func TestBroadcastEvidence_ConflictingHeadersEvidence(t *testing.T) {
   158  	var (
   159  		config  = rpctest.GetConfig()
   160  		chainID = config.ChainID()
   161  		pv      = privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
   162  	)
   163  
   164  	for i, c := range GetClients() {
   165  		t.Logf("client %d", i)
   166  
   167  		h1, err := c.Commit(nil)
   168  		require.NoError(t, err)
   169  		require.NotNil(t, h1.SignedHeader.Header)
   170  
   171  		// Create an alternative header with a different AppHash.
   172  		h2 := &types.SignedHeader{
   173  			Header: &types.Header{
   174  				Version:            h1.Version,
   175  				ChainID:            h1.ChainID,
   176  				Height:             h1.Height,
   177  				Time:               h1.Time,
   178  				LastBlockID:        h1.LastBlockID,
   179  				LastCommitHash:     h1.LastCommitHash,
   180  				DataHash:           h1.DataHash,
   181  				ValidatorsHash:     h1.ValidatorsHash,
   182  				NextValidatorsHash: h1.NextValidatorsHash,
   183  				ConsensusHash:      h1.ConsensusHash,
   184  				AppHash:            crypto.CRandBytes(32),
   185  				LastResultsHash:    h1.LastResultsHash,
   186  				EvidenceHash:       h1.EvidenceHash,
   187  				ProposerAddress:    h1.ProposerAddress,
   188  			},
   189  			Commit: types.NewCommit(h1.Height, 1, h1.Commit.BlockID, h1.Commit.Signatures),
   190  		}
   191  		h2.Commit.BlockID = types.BlockID{
   192  			Hash:          h2.Hash(),
   193  			PartSetHeader: types.PartSetHeader{Total: 1, Hash: crypto.CRandBytes(32)},
   194  		}
   195  		vote := &types.Vote{
   196  			ValidatorAddress: pv.Key.Address,
   197  			ValidatorIndex:   0,
   198  			Height:           h2.Height,
   199  			Round:            h2.Commit.Round,
   200  			Timestamp:        h2.Time,
   201  			Type:             tmproto.PrecommitType,
   202  			BlockID:          h2.Commit.BlockID,
   203  		}
   204  
   205  		v := vote.ToProto()
   206  		signBytes, err := pv.Key.PrivKey.Sign(types.VoteSignBytes(chainID, v))
   207  		require.NoError(t, err)
   208  		vote.Signature = v.Signature
   209  
   210  		h2.Commit.Signatures[0] = types.NewCommitSigForBlock(signBytes, pv.Key.Address, h2.Time)
   211  
   212  		t.Logf("h1 AppHash: %X", h1.AppHash)
   213  		t.Logf("h2 AppHash: %X", h2.AppHash)
   214  
   215  		ev := &types.ConflictingHeadersEvidence{
   216  			H1: &h1.SignedHeader,
   217  			H2: h2,
   218  		}
   219  
   220  		result, err := c.BroadcastEvidence(ev)
   221  		require.NoError(t, err, "BroadcastEvidence(%s) failed", ev)
   222  		assert.Equal(t, ev.Hash(), result.Hash, "expected result hash to match evidence hash")
   223  	}
   224  }
   225  
   226  func TestBroadcastEmptyEvidence(t *testing.T) {
   227  	for _, c := range GetClients() {
   228  		_, err := c.BroadcastEvidence(nil)
   229  		assert.Error(t, err)
   230  	}
   231  }