|
|
@ -1,7 +1,9 @@ |
|
|
|
package client_test |
|
|
|
|
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"fmt" |
|
|
|
"math/rand" |
|
|
|
"net/http" |
|
|
|
"strings" |
|
|
|
"sync" |
|
|
@ -12,7 +14,10 @@ import ( |
|
|
|
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types" |
|
|
|
|
|
|
|
"github.com/tendermint/tendermint/crypto/ed25519" |
|
|
|
"github.com/tendermint/tendermint/crypto/tmhash" |
|
|
|
cmn "github.com/tendermint/tendermint/libs/common" |
|
|
|
"github.com/tendermint/tendermint/privval" |
|
|
|
"github.com/tendermint/tendermint/rpc/client" |
|
|
|
ctypes "github.com/tendermint/tendermint/rpc/core/types" |
|
|
|
rpctest "github.com/tendermint/tendermint/rpc/test" |
|
|
@ -446,6 +451,145 @@ func TestTxSearch(t *testing.T) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func deepcpVote(vote *types.Vote) (res *types.Vote) { |
|
|
|
res = &types.Vote{ |
|
|
|
ValidatorAddress: make([]byte, len(vote.ValidatorAddress)), |
|
|
|
ValidatorIndex: vote.ValidatorIndex, |
|
|
|
Height: vote.Height, |
|
|
|
Round: vote.Round, |
|
|
|
Type: vote.Type, |
|
|
|
BlockID: types.BlockID{ |
|
|
|
Hash: make([]byte, len(vote.BlockID.Hash)), |
|
|
|
PartsHeader: vote.BlockID.PartsHeader, |
|
|
|
}, |
|
|
|
Signature: make([]byte, len(vote.Signature)), |
|
|
|
} |
|
|
|
copy(res.ValidatorAddress, vote.ValidatorAddress) |
|
|
|
copy(res.BlockID.Hash, vote.BlockID.Hash) |
|
|
|
copy(res.Signature, vote.Signature) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func newEvidence(t *testing.T, val *privval.FilePV, vote *types.Vote, vote2 *types.Vote, chainID string) types.DuplicateVoteEvidence { |
|
|
|
var err error |
|
|
|
vote2_ := deepcpVote(vote2) |
|
|
|
vote2_.Signature, err = val.Key.PrivKey.Sign(vote2_.SignBytes(chainID)) |
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
return types.DuplicateVoteEvidence{ |
|
|
|
PubKey: val.Key.PubKey, |
|
|
|
VoteA: vote, |
|
|
|
VoteB: vote2_, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func makeEvidences(t *testing.T, val *privval.FilePV, chainID string) (ev types.DuplicateVoteEvidence, fakes []types.DuplicateVoteEvidence) { |
|
|
|
vote := &types.Vote{ |
|
|
|
ValidatorAddress: val.Key.Address, |
|
|
|
ValidatorIndex: 0, |
|
|
|
Height: 1, |
|
|
|
Round: 0, |
|
|
|
Type: types.PrevoteType, |
|
|
|
BlockID: types.BlockID{ |
|
|
|
Hash: tmhash.Sum([]byte("blockhash")), |
|
|
|
PartsHeader: types.PartSetHeader{ |
|
|
|
Total: 1000, |
|
|
|
Hash: tmhash.Sum([]byte("partset")), |
|
|
|
}, |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
var err error |
|
|
|
vote.Signature, err = val.Key.PrivKey.Sign(vote.SignBytes(chainID)) |
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
vote2 := deepcpVote(vote) |
|
|
|
vote2.BlockID.Hash = tmhash.Sum([]byte("blockhash2")) |
|
|
|
|
|
|
|
ev = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
|
|
|
|
fakes = make([]types.DuplicateVoteEvidence, 42) |
|
|
|
|
|
|
|
// different address
|
|
|
|
vote2 = deepcpVote(vote) |
|
|
|
for i := 0; i < 10; i++ { |
|
|
|
rand.Read(vote2.ValidatorAddress) // nolint: gosec
|
|
|
|
fakes[i] = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
} |
|
|
|
// different index
|
|
|
|
vote2 = deepcpVote(vote) |
|
|
|
for i := 10; i < 20; i++ { |
|
|
|
vote2.ValidatorIndex = rand.Int()%100 + 1 // nolint: gosec
|
|
|
|
fakes[i] = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
} |
|
|
|
// different height
|
|
|
|
vote2 = deepcpVote(vote) |
|
|
|
for i := 20; i < 30; i++ { |
|
|
|
vote2.Height = rand.Int63()%1000 + 100 // nolint: gosec
|
|
|
|
fakes[i] = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
} |
|
|
|
// different round
|
|
|
|
vote2 = deepcpVote(vote) |
|
|
|
for i := 30; i < 40; i++ { |
|
|
|
vote2.Round = rand.Int()%10 + 1 // nolint: gosec
|
|
|
|
fakes[i] = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
} |
|
|
|
// different type
|
|
|
|
vote2 = deepcpVote(vote) |
|
|
|
vote2.Type = types.PrecommitType |
|
|
|
fakes[40] = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
// exactly same vote
|
|
|
|
vote2 = deepcpVote(vote) |
|
|
|
fakes[41] = newEvidence(t, val, vote, vote2, chainID) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func TestBroadcastEvidenceDuplicateVote(t *testing.T) { |
|
|
|
config := rpctest.GetConfig() |
|
|
|
chainID := config.ChainID() |
|
|
|
pvKeyFile := config.PrivValidatorKeyFile() |
|
|
|
pvKeyStateFile := config.PrivValidatorStateFile() |
|
|
|
pv := privval.LoadOrGenFilePV(pvKeyFile, pvKeyStateFile) |
|
|
|
|
|
|
|
ev, fakes := makeEvidences(t, pv, chainID) |
|
|
|
|
|
|
|
t.Logf("evidence %v", ev) |
|
|
|
|
|
|
|
for i, c := range GetClients() { |
|
|
|
t.Logf("client %d", i) |
|
|
|
|
|
|
|
result, err := c.BroadcastEvidence(&types.DuplicateVoteEvidence{PubKey: ev.PubKey, VoteA: ev.VoteA, VoteB: ev.VoteB}) |
|
|
|
require.Nil(t, err) |
|
|
|
require.Equal(t, ev.Hash(), result.Hash, "Invalid response, result %+v", result) |
|
|
|
|
|
|
|
status, err := c.Status() |
|
|
|
require.NoError(t, err) |
|
|
|
client.WaitForHeight(c, status.SyncInfo.LatestBlockHeight+2, nil) |
|
|
|
|
|
|
|
ed25519pub := ev.PubKey.(ed25519.PubKeyEd25519) |
|
|
|
rawpub := ed25519pub[:] |
|
|
|
result2, err := c.ABCIQuery("/val", rawpub) |
|
|
|
require.Nil(t, err, "Error querying evidence, err %v", err) |
|
|
|
qres := result2.Response |
|
|
|
require.True(t, qres.IsOK(), "Response not OK") |
|
|
|
|
|
|
|
var v abci.ValidatorUpdate |
|
|
|
err = abci.ReadMessage(bytes.NewReader(qres.Value), &v) |
|
|
|
require.NoError(t, err, "Error reading query result, value %v", qres.Value) |
|
|
|
|
|
|
|
require.EqualValues(t, rawpub, v.PubKey.Data, "Stored PubKey not equal with expected, value %v", string(qres.Value)) |
|
|
|
require.Equal(t, int64(9), v.Power, "Stored Power not equal with expected, value %v", string(qres.Value)) |
|
|
|
|
|
|
|
for _, fake := range fakes { |
|
|
|
_, err := c.BroadcastEvidence(&types.DuplicateVoteEvidence{ |
|
|
|
PubKey: fake.PubKey, |
|
|
|
VoteA: fake.VoteA, |
|
|
|
VoteB: fake.VoteB}) |
|
|
|
require.Error(t, err, "Broadcasting fake evidence succeed: %s", fake.String()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func TestBatchedJSONRPCCalls(t *testing.T) { |
|
|
|
c := getHTTPClient() |
|
|
|
testBatchedJSONRPCCalls(t, c) |
|
|
|