mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-12 04:41:22 +00:00
rpc: /broadcast_evidence (#3481)
* implement broadcast_duplicate_vote endpoint * fix test_cover * address comments * address comments * Update abci/example/kvstore/persistent_kvstore.go Co-Authored-By: mossid <torecursedivine@gmail.com> * Update rpc/client/main_test.go Co-Authored-By: mossid <torecursedivine@gmail.com> * address comments in progress * reformat the code * make linter happy * make tests pass * replace BroadcastDuplicateVote with BroadcastEvidence * fix test * fix endpoint name * improve doc * fix TestBroadcastEvidenceDuplicateVote * Update rpc/core/evidence.go Co-Authored-By: Thane Thomson <connect@thanethomson.com> * add changelog entry * fix TestBroadcastEvidenceDuplicateVote
This commit is contained in:
@ -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)
|
||||
|
Reference in New Issue
Block a user