github.com/DFWallet/tendermint-cosmos@v0.0.2/privval/file_test.go (about)

     1  package privval
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/DFWallet/tendermint-cosmos/crypto/ed25519"
    15  	"github.com/DFWallet/tendermint-cosmos/crypto/tmhash"
    16  	tmjson "github.com/DFWallet/tendermint-cosmos/libs/json"
    17  	tmrand "github.com/DFWallet/tendermint-cosmos/libs/rand"
    18  	tmproto "github.com/DFWallet/tendermint-cosmos/proto/tendermint/types"
    19  	"github.com/DFWallet/tendermint-cosmos/types"
    20  	tmtime "github.com/DFWallet/tendermint-cosmos/types/time"
    21  )
    22  
    23  func TestGenLoadValidator(t *testing.T) {
    24  	assert := assert.New(t)
    25  
    26  	tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
    27  	require.Nil(t, err)
    28  	tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
    29  	require.Nil(t, err)
    30  
    31  	privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
    32  
    33  	height := int64(100)
    34  	privVal.LastSignState.Height = height
    35  	privVal.Save()
    36  	addr := privVal.GetAddress()
    37  
    38  	privVal = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name())
    39  	assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
    40  	assert.Equal(height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved")
    41  }
    42  
    43  func TestResetValidator(t *testing.T) {
    44  	tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
    45  	require.Nil(t, err)
    46  	tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
    47  	require.Nil(t, err)
    48  
    49  	privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
    50  	emptyState := FilePVLastSignState{filePath: tempStateFile.Name()}
    51  
    52  	// new priv val has empty state
    53  	assert.Equal(t, privVal.LastSignState, emptyState)
    54  
    55  	// test vote
    56  	height, round := int64(10), int32(1)
    57  	voteType := tmproto.PrevoteType
    58  	randBytes := tmrand.Bytes(tmhash.Size)
    59  	blockID := types.BlockID{Hash: randBytes, PartSetHeader: types.PartSetHeader{}}
    60  	vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID)
    61  	err = privVal.SignVote("mychainid", vote.ToProto())
    62  	assert.NoError(t, err, "expected no error signing vote")
    63  
    64  	// priv val after signing is not same as empty
    65  	assert.NotEqual(t, privVal.LastSignState, emptyState)
    66  
    67  	// priv val after AcceptNewConnection is same as empty
    68  	privVal.Reset()
    69  	assert.Equal(t, privVal.LastSignState, emptyState)
    70  }
    71  
    72  func TestLoadOrGenValidator(t *testing.T) {
    73  	assert := assert.New(t)
    74  
    75  	tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
    76  	require.Nil(t, err)
    77  	tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
    78  	require.Nil(t, err)
    79  
    80  	tempKeyFilePath := tempKeyFile.Name()
    81  	if err := os.Remove(tempKeyFilePath); err != nil {
    82  		t.Error(err)
    83  	}
    84  	tempStateFilePath := tempStateFile.Name()
    85  	if err := os.Remove(tempStateFilePath); err != nil {
    86  		t.Error(err)
    87  	}
    88  
    89  	privVal := LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath)
    90  	addr := privVal.GetAddress()
    91  	privVal = LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath)
    92  	assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
    93  }
    94  
    95  func TestUnmarshalValidatorState(t *testing.T) {
    96  	assert, require := assert.New(t), require.New(t)
    97  
    98  	// create some fixed values
    99  	serialized := `{
   100  		"height": "1",
   101  		"round": 1,
   102  		"step": 1
   103  	}`
   104  
   105  	val := FilePVLastSignState{}
   106  	err := tmjson.Unmarshal([]byte(serialized), &val)
   107  	require.Nil(err, "%+v", err)
   108  
   109  	// make sure the values match
   110  	assert.EqualValues(val.Height, 1)
   111  	assert.EqualValues(val.Round, 1)
   112  	assert.EqualValues(val.Step, 1)
   113  
   114  	// export it and make sure it is the same
   115  	out, err := tmjson.Marshal(val)
   116  	require.Nil(err, "%+v", err)
   117  	assert.JSONEq(serialized, string(out))
   118  }
   119  
   120  func TestUnmarshalValidatorKey(t *testing.T) {
   121  	assert, require := assert.New(t), require.New(t)
   122  
   123  	// create some fixed values
   124  	privKey := ed25519.GenPrivKey()
   125  	pubKey := privKey.PubKey()
   126  	addr := pubKey.Address()
   127  	pubBytes := pubKey.Bytes()
   128  	privBytes := privKey.Bytes()
   129  	pubB64 := base64.StdEncoding.EncodeToString(pubBytes)
   130  	privB64 := base64.StdEncoding.EncodeToString(privBytes)
   131  
   132  	serialized := fmt.Sprintf(`{
   133    "address": "%s",
   134    "pub_key": {
   135      "type": "tendermint/PubKeyEd25519",
   136      "value": "%s"
   137    },
   138    "priv_key": {
   139      "type": "tendermint/PrivKeyEd25519",
   140      "value": "%s"
   141    }
   142  }`, addr, pubB64, privB64)
   143  
   144  	val := FilePVKey{}
   145  	err := tmjson.Unmarshal([]byte(serialized), &val)
   146  	require.Nil(err, "%+v", err)
   147  
   148  	// make sure the values match
   149  	assert.EqualValues(addr, val.Address)
   150  	assert.EqualValues(pubKey, val.PubKey)
   151  	assert.EqualValues(privKey, val.PrivKey)
   152  
   153  	// export it and make sure it is the same
   154  	out, err := tmjson.Marshal(val)
   155  	require.Nil(err, "%+v", err)
   156  	assert.JSONEq(serialized, string(out))
   157  }
   158  
   159  func TestSignVote(t *testing.T) {
   160  	assert := assert.New(t)
   161  
   162  	tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
   163  	require.Nil(t, err)
   164  	tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
   165  	require.Nil(t, err)
   166  
   167  	privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
   168  
   169  	randbytes := tmrand.Bytes(tmhash.Size)
   170  	randbytes2 := tmrand.Bytes(tmhash.Size)
   171  
   172  	block1 := types.BlockID{Hash: randbytes,
   173  		PartSetHeader: types.PartSetHeader{Total: 5, Hash: randbytes}}
   174  	block2 := types.BlockID{Hash: randbytes2,
   175  		PartSetHeader: types.PartSetHeader{Total: 10, Hash: randbytes2}}
   176  
   177  	height, round := int64(10), int32(1)
   178  	voteType := tmproto.PrevoteType
   179  
   180  	// sign a vote for first time
   181  	vote := newVote(privVal.Key.Address, 0, height, round, voteType, block1)
   182  	v := vote.ToProto()
   183  	err = privVal.SignVote("mychainid", v)
   184  	assert.NoError(err, "expected no error signing vote")
   185  
   186  	// try to sign the same vote again; should be fine
   187  	err = privVal.SignVote("mychainid", v)
   188  	assert.NoError(err, "expected no error on signing same vote")
   189  
   190  	// now try some bad votes
   191  	cases := []*types.Vote{
   192  		newVote(privVal.Key.Address, 0, height, round-1, voteType, block1),   // round regression
   193  		newVote(privVal.Key.Address, 0, height-1, round, voteType, block1),   // height regression
   194  		newVote(privVal.Key.Address, 0, height-2, round+4, voteType, block1), // height regression and different round
   195  		newVote(privVal.Key.Address, 0, height, round, voteType, block2),     // different block
   196  	}
   197  
   198  	for _, c := range cases {
   199  		cpb := c.ToProto()
   200  		err = privVal.SignVote("mychainid", cpb)
   201  		assert.Error(err, "expected error on signing conflicting vote")
   202  	}
   203  
   204  	// try signing a vote with a different time stamp
   205  	sig := vote.Signature
   206  	vote.Timestamp = vote.Timestamp.Add(time.Duration(1000))
   207  	err = privVal.SignVote("mychainid", v)
   208  	assert.NoError(err)
   209  	assert.Equal(sig, vote.Signature)
   210  }
   211  
   212  func TestSignProposal(t *testing.T) {
   213  	assert := assert.New(t)
   214  
   215  	tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
   216  	require.Nil(t, err)
   217  	tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
   218  	require.Nil(t, err)
   219  
   220  	privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
   221  
   222  	randbytes := tmrand.Bytes(tmhash.Size)
   223  	randbytes2 := tmrand.Bytes(tmhash.Size)
   224  
   225  	block1 := types.BlockID{Hash: randbytes,
   226  		PartSetHeader: types.PartSetHeader{Total: 5, Hash: randbytes}}
   227  	block2 := types.BlockID{Hash: randbytes2,
   228  		PartSetHeader: types.PartSetHeader{Total: 10, Hash: randbytes2}}
   229  	height, round := int64(10), int32(1)
   230  
   231  	// sign a proposal for first time
   232  	proposal := newProposal(height, round, block1)
   233  	pbp := proposal.ToProto()
   234  	err = privVal.SignProposal("mychainid", pbp)
   235  	assert.NoError(err, "expected no error signing proposal")
   236  
   237  	// try to sign the same proposal again; should be fine
   238  	err = privVal.SignProposal("mychainid", pbp)
   239  	assert.NoError(err, "expected no error on signing same proposal")
   240  
   241  	// now try some bad Proposals
   242  	cases := []*types.Proposal{
   243  		newProposal(height, round-1, block1),   // round regression
   244  		newProposal(height-1, round, block1),   // height regression
   245  		newProposal(height-2, round+4, block1), // height regression and different round
   246  		newProposal(height, round, block2),     // different block
   247  	}
   248  
   249  	for _, c := range cases {
   250  		err = privVal.SignProposal("mychainid", c.ToProto())
   251  		assert.Error(err, "expected error on signing conflicting proposal")
   252  	}
   253  
   254  	// try signing a proposal with a different time stamp
   255  	sig := proposal.Signature
   256  	proposal.Timestamp = proposal.Timestamp.Add(time.Duration(1000))
   257  	err = privVal.SignProposal("mychainid", pbp)
   258  	assert.NoError(err)
   259  	assert.Equal(sig, proposal.Signature)
   260  }
   261  
   262  func TestDifferByTimestamp(t *testing.T) {
   263  	tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
   264  	require.Nil(t, err)
   265  	tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
   266  	require.Nil(t, err)
   267  
   268  	privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
   269  	randbytes := tmrand.Bytes(tmhash.Size)
   270  	block1 := types.BlockID{Hash: randbytes, PartSetHeader: types.PartSetHeader{Total: 5, Hash: randbytes}}
   271  	height, round := int64(10), int32(1)
   272  	chainID := "mychainid"
   273  
   274  	// test proposal
   275  	{
   276  		proposal := newProposal(height, round, block1)
   277  		pb := proposal.ToProto()
   278  		err := privVal.SignProposal(chainID, pb)
   279  		assert.NoError(t, err, "expected no error signing proposal")
   280  		signBytes := types.ProposalSignBytes(chainID, pb)
   281  
   282  		sig := proposal.Signature
   283  		timeStamp := proposal.Timestamp
   284  
   285  		// manipulate the timestamp. should get changed back
   286  		pb.Timestamp = pb.Timestamp.Add(time.Millisecond)
   287  		var emptySig []byte
   288  		proposal.Signature = emptySig
   289  		err = privVal.SignProposal("mychainid", pb)
   290  		assert.NoError(t, err, "expected no error on signing same proposal")
   291  
   292  		assert.Equal(t, timeStamp, pb.Timestamp)
   293  		assert.Equal(t, signBytes, types.ProposalSignBytes(chainID, pb))
   294  		assert.Equal(t, sig, proposal.Signature)
   295  	}
   296  
   297  	// test vote
   298  	{
   299  		voteType := tmproto.PrevoteType
   300  		blockID := types.BlockID{Hash: randbytes, PartSetHeader: types.PartSetHeader{}}
   301  		vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID)
   302  		v := vote.ToProto()
   303  		err := privVal.SignVote("mychainid", v)
   304  		assert.NoError(t, err, "expected no error signing vote")
   305  
   306  		signBytes := types.VoteSignBytes(chainID, v)
   307  		sig := v.Signature
   308  		timeStamp := vote.Timestamp
   309  
   310  		// manipulate the timestamp. should get changed back
   311  		v.Timestamp = v.Timestamp.Add(time.Millisecond)
   312  		var emptySig []byte
   313  		v.Signature = emptySig
   314  		err = privVal.SignVote("mychainid", v)
   315  		assert.NoError(t, err, "expected no error on signing same vote")
   316  
   317  		assert.Equal(t, timeStamp, v.Timestamp)
   318  		assert.Equal(t, signBytes, types.VoteSignBytes(chainID, v))
   319  		assert.Equal(t, sig, v.Signature)
   320  	}
   321  }
   322  
   323  func newVote(addr types.Address, idx int32, height int64, round int32,
   324  	typ tmproto.SignedMsgType, blockID types.BlockID) *types.Vote {
   325  	return &types.Vote{
   326  		ValidatorAddress: addr,
   327  		ValidatorIndex:   idx,
   328  		Height:           height,
   329  		Round:            round,
   330  		Type:             typ,
   331  		Timestamp:        tmtime.Now(),
   332  		BlockID:          blockID,
   333  	}
   334  }
   335  
   336  func newProposal(height int64, round int32, blockID types.BlockID) *types.Proposal {
   337  	return &types.Proposal{
   338  		Height:    height,
   339  		Round:     round,
   340  		BlockID:   blockID,
   341  		Timestamp: tmtime.Now(),
   342  	}
   343  }