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 }