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