mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-08 06:15:33 +00:00
privval: migrate to protobuf (#4985)
This commit is contained in:
@@ -773,7 +773,8 @@ func (commit *Commit) GetVote(valIdx int32) *Vote {
|
||||
// signed over are otherwise the same for all validators.
|
||||
// Panics if valIdx >= commit.Size().
|
||||
func (commit *Commit) VoteSignBytes(chainID string, valIdx int32) []byte {
|
||||
return commit.GetVote(valIdx).SignBytes(chainID)
|
||||
v := commit.GetVote(valIdx).ToProto()
|
||||
return VoteSignBytes(chainID, v)
|
||||
}
|
||||
|
||||
// Type returns the vote type of the commit, which is always VoteTypePrecommit
|
||||
|
||||
@@ -378,9 +378,9 @@ func TestBlockMaxDataBytes(t *testing.T) {
|
||||
}{
|
||||
0: {-10, 1, 0, true, 0},
|
||||
1: {10, 1, 0, true, 0},
|
||||
2: {849, 1, 0, true, 0},
|
||||
3: {850, 1, 0, false, 0},
|
||||
4: {851, 1, 0, false, 1},
|
||||
2: {846, 1, 0, true, 0},
|
||||
3: {848, 1, 0, false, 0},
|
||||
4: {849, 1, 0, false, 1},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
@@ -408,10 +408,10 @@ func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) {
|
||||
}{
|
||||
0: {-10, 0, 1, true, 0},
|
||||
1: {10, 0, 1, true, 0},
|
||||
2: {849, 0, 1, true, 0},
|
||||
3: {850, 0, 1, false, 0},
|
||||
4: {1294, 1, 1, false, 0},
|
||||
5: {1295, 1, 1, false, 1},
|
||||
2: {847, 0, 1, true, 0},
|
||||
3: {848, 0, 1, false, 0},
|
||||
4: {1292, 1, 1, false, 0},
|
||||
5: {1293, 1, 1, false, 1},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
|
||||
@@ -3,7 +3,6 @@ package types
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/bytes"
|
||||
tmproto "github.com/tendermint/tendermint/proto/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
)
|
||||
@@ -13,66 +12,37 @@ import (
|
||||
// TimeFormat is used for generating the sigs
|
||||
const TimeFormat = time.RFC3339Nano
|
||||
|
||||
type CanonicalBlockID struct {
|
||||
Hash bytes.HexBytes
|
||||
PartsHeader CanonicalPartSetHeader
|
||||
}
|
||||
|
||||
type CanonicalPartSetHeader struct {
|
||||
Hash bytes.HexBytes
|
||||
Total uint32
|
||||
}
|
||||
|
||||
type CanonicalProposal struct {
|
||||
Type tmproto.SignedMsgType // type alias for byte
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
POLRound int64 `binary:"fixed64"`
|
||||
BlockID CanonicalBlockID
|
||||
Timestamp time.Time
|
||||
ChainID string
|
||||
}
|
||||
|
||||
type CanonicalVote struct {
|
||||
Type tmproto.SignedMsgType // type alias for byte
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
BlockID CanonicalBlockID
|
||||
Timestamp time.Time
|
||||
ChainID string
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Canonicalize the structs
|
||||
|
||||
func CanonicalizeBlockID(blockID BlockID) CanonicalBlockID {
|
||||
return CanonicalBlockID{
|
||||
func CanonicalizeBlockID(blockID tmproto.BlockID) tmproto.CanonicalBlockID {
|
||||
return tmproto.CanonicalBlockID{
|
||||
Hash: blockID.Hash,
|
||||
PartsHeader: CanonicalizePartSetHeader(blockID.PartsHeader),
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalizePartSetHeader(psh PartSetHeader) CanonicalPartSetHeader {
|
||||
return CanonicalPartSetHeader{
|
||||
psh.Hash,
|
||||
psh.Total,
|
||||
func CanonicalizePartSetHeader(psh tmproto.PartSetHeader) tmproto.CanonicalPartSetHeader {
|
||||
return tmproto.CanonicalPartSetHeader{
|
||||
Hash: psh.Hash,
|
||||
Total: psh.Total,
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalizeProposal(chainID string, proposal *Proposal) CanonicalProposal {
|
||||
return CanonicalProposal{
|
||||
func CanonicalizeProposal(chainID string, proposal *tmproto.Proposal) tmproto.CanonicalProposal {
|
||||
return tmproto.CanonicalProposal{
|
||||
Type: tmproto.ProposalType,
|
||||
Height: proposal.Height,
|
||||
Round: int64(proposal.Round), // cast int->int64 to make amino encode it fixed64 (does not work for int)
|
||||
POLRound: int64(proposal.POLRound),
|
||||
POLRound: int64(proposal.PolRound),
|
||||
BlockID: CanonicalizeBlockID(proposal.BlockID),
|
||||
Timestamp: proposal.Timestamp,
|
||||
ChainID: chainID,
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalizeVote(chainID string, vote *Vote) CanonicalVote {
|
||||
return CanonicalVote{
|
||||
func CanonicalizeVote(chainID string, vote *tmproto.Vote) tmproto.CanonicalVote {
|
||||
return tmproto.CanonicalVote{
|
||||
Type: vote.Type,
|
||||
Height: vote.Height,
|
||||
Round: int64(vote.Round), // cast int->int64 to make amino encode it fixed64 (does not work for int)
|
||||
|
||||
@@ -463,12 +463,13 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string, pubKey crypto.PubKey) e
|
||||
return fmt.Errorf("address (%X) doesn't match pubkey (%v - %X)",
|
||||
addr, pubKey, pubKey.Address())
|
||||
}
|
||||
|
||||
va := dve.VoteA.ToProto()
|
||||
vb := dve.VoteB.ToProto()
|
||||
// Signatures must be valid
|
||||
if !pubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, va), dve.VoteA.Signature) {
|
||||
return fmt.Errorf("verifying VoteA: %w", ErrVoteInvalidSignature)
|
||||
}
|
||||
if !pubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, vb), dve.VoteB.Signature) {
|
||||
return fmt.Errorf("verifying VoteB: %w", ErrVoteInvalidSignature)
|
||||
}
|
||||
|
||||
@@ -841,8 +842,8 @@ func (e PhantomValidatorEvidence) Bytes() []byte {
|
||||
|
||||
func (e PhantomValidatorEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
|
||||
// signature must be verified to the chain ID
|
||||
if !pubKey.VerifyBytes(e.Vote.SignBytes(chainID), e.Vote.Signature) {
|
||||
v := e.Vote.ToProto()
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, v), e.Vote.Signature) {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
||||
@@ -930,7 +931,8 @@ func (e LunaticValidatorEvidence) Verify(chainID string, pubKey crypto.PubKey) e
|
||||
)
|
||||
}
|
||||
|
||||
if !pubKey.VerifyBytes(e.Vote.SignBytes(chainID), e.Vote.Signature) {
|
||||
v := e.Vote.ToProto()
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, v), e.Vote.Signature) {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
||||
@@ -1072,11 +1074,14 @@ func (e PotentialAmnesiaEvidence) Verify(chainID string, pubKey crypto.PubKey) e
|
||||
addr, pubKey, pubKey.Address())
|
||||
}
|
||||
|
||||
va := e.VoteA.ToProto()
|
||||
vb := e.VoteB.ToProto()
|
||||
|
||||
// Signatures must be valid
|
||||
if !pubKey.VerifyBytes(e.VoteA.SignBytes(chainID), e.VoteA.Signature) {
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, va), e.VoteA.Signature) {
|
||||
return fmt.Errorf("verifying VoteA: %w", ErrVoteInvalidSignature)
|
||||
}
|
||||
if !pubKey.VerifyBytes(e.VoteB.SignBytes(chainID), e.VoteB.Signature) {
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, vb), e.VoteB.Signature) {
|
||||
return fmt.Errorf("verifying VoteB: %w", ErrVoteInvalidSignature)
|
||||
}
|
||||
|
||||
@@ -1247,7 +1252,8 @@ func (e ProofOfLockChange) ValidateVotes(valSet *ValidatorSet, chainID string) e
|
||||
for _, validator := range valSet.Validators {
|
||||
if bytes.Equal(validator.Address, vote.ValidatorAddress) {
|
||||
exists = true
|
||||
if !validator.PubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
|
||||
v := vote.ToProto()
|
||||
if !validator.PubKey.VerifyBytes(VoteSignBytes(chainID, v), vote.Signature) {
|
||||
return fmt.Errorf("cannot verify vote (from validator: %d) against signature: %v",
|
||||
vote.ValidatorIndex, vote.Signature)
|
||||
}
|
||||
@@ -1615,7 +1621,13 @@ func NewMockPOLC(height int64, time time.Time, pubKey crypto.PubKey) ProofOfLock
|
||||
pKey, _ := voteVal.GetPubKey()
|
||||
vote := Vote{Type: tmproto.PrecommitType, Height: height, Round: 1, BlockID: BlockID{},
|
||||
Timestamp: time, ValidatorAddress: pKey.Address(), ValidatorIndex: 1, Signature: []byte{}}
|
||||
_ = voteVal.SignVote("mock-chain-id", &vote)
|
||||
|
||||
v := vote.ToProto()
|
||||
if err := voteVal.SignVote("mock-chain-id", v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vote.Signature = v.Signature
|
||||
|
||||
return ProofOfLockChange{
|
||||
Votes: []Vote{vote},
|
||||
PubKey: pubKey,
|
||||
|
||||
@@ -34,12 +34,17 @@ func TestEvidence(t *testing.T) {
|
||||
const chainID = "mychain"
|
||||
|
||||
vote1 := makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime)
|
||||
err := val.SignVote(chainID, vote1)
|
||||
v1 := vote1.ToProto()
|
||||
err := val.SignVote(chainID, v1)
|
||||
require.NoError(t, err)
|
||||
badVote := makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime)
|
||||
err = val2.SignVote(chainID, badVote)
|
||||
bv := badVote.ToProto()
|
||||
err = val2.SignVote(chainID, bv)
|
||||
require.NoError(t, err)
|
||||
|
||||
vote1.Signature = v1.Signature
|
||||
badVote.Signature = bv.Signature
|
||||
|
||||
cases := []voteData{
|
||||
{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime), true}, // different block ids
|
||||
{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID3, defaultVoteTime), true},
|
||||
@@ -542,10 +547,13 @@ func makeVote(
|
||||
BlockID: blockID,
|
||||
Timestamp: time,
|
||||
}
|
||||
err = val.SignVote(chainID, v)
|
||||
|
||||
vpb := v.ToProto()
|
||||
err = val.SignVote(chainID, vpb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
v.Signature = vpb.Signature
|
||||
return v
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
tmproto "github.com/tendermint/tendermint/proto/types"
|
||||
)
|
||||
|
||||
// PrivValidator defines the functionality of a local Tendermint validator
|
||||
@@ -14,8 +15,8 @@ import (
|
||||
type PrivValidator interface {
|
||||
GetPubKey() (crypto.PubKey, error)
|
||||
|
||||
SignVote(chainID string, vote *Vote) error
|
||||
SignProposal(chainID string, proposal *Proposal) error
|
||||
SignVote(chainID string, vote *tmproto.Vote) error
|
||||
SignProposal(chainID string, proposal *tmproto.Proposal) error
|
||||
}
|
||||
|
||||
type PrivValidatorsByAddress []PrivValidator
|
||||
@@ -71,12 +72,13 @@ func (pv MockPV) GetPubKey() (crypto.PubKey, error) {
|
||||
}
|
||||
|
||||
// Implements PrivValidator.
|
||||
func (pv MockPV) SignVote(chainID string, vote *Vote) error {
|
||||
func (pv MockPV) SignVote(chainID string, vote *tmproto.Vote) error {
|
||||
useChainID := chainID
|
||||
if pv.breakVoteSigning {
|
||||
useChainID = "incorrect-chain-id"
|
||||
}
|
||||
signBytes := vote.SignBytes(useChainID)
|
||||
|
||||
signBytes := VoteSignBytes(useChainID, vote)
|
||||
sig, err := pv.PrivKey.Sign(signBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -86,12 +88,13 @@ func (pv MockPV) SignVote(chainID string, vote *Vote) error {
|
||||
}
|
||||
|
||||
// Implements PrivValidator.
|
||||
func (pv MockPV) SignProposal(chainID string, proposal *Proposal) error {
|
||||
func (pv MockPV) SignProposal(chainID string, proposal *tmproto.Proposal) error {
|
||||
useChainID := chainID
|
||||
if pv.breakProposalSigning {
|
||||
useChainID = "incorrect-chain-id"
|
||||
}
|
||||
signBytes := proposal.SignBytes(useChainID)
|
||||
|
||||
signBytes := ProposalSignBytes(useChainID, proposal)
|
||||
sig, err := pv.PrivKey.Sign(signBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -128,12 +131,12 @@ type ErroringMockPV struct {
|
||||
var ErroringMockPVErr = errors.New("erroringMockPV always returns an error")
|
||||
|
||||
// Implements PrivValidator.
|
||||
func (pv *ErroringMockPV) SignVote(chainID string, vote *Vote) error {
|
||||
func (pv *ErroringMockPV) SignVote(chainID string, vote *tmproto.Vote) error {
|
||||
return ErroringMockPVErr
|
||||
}
|
||||
|
||||
// Implements PrivValidator.
|
||||
func (pv *ErroringMockPV) SignProposal(chainID string, proposal *Proposal) error {
|
||||
func (pv *ErroringMockPV) SignProposal(chainID string, proposal *tmproto.Proposal) error {
|
||||
return ErroringMockPVErr
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/bytes"
|
||||
tmproto "github.com/tendermint/tendermint/proto/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
@@ -71,6 +73,7 @@ func (p *Proposal) ValidateBasic() error {
|
||||
if len(p.Signature) == 0 {
|
||||
return errors.New("signature is missing")
|
||||
}
|
||||
|
||||
if len(p.Signature) > MaxSignatureSize {
|
||||
return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
|
||||
}
|
||||
@@ -88,9 +91,10 @@ func (p *Proposal) String() string {
|
||||
CanonicalTime(p.Timestamp))
|
||||
}
|
||||
|
||||
// SignBytes returns the Proposal bytes for signing
|
||||
func (p *Proposal) SignBytes(chainID string) []byte {
|
||||
bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeProposal(chainID, p))
|
||||
// ProposalSignBytes returns the Proposal bytes for signing
|
||||
func ProposalSignBytes(chainID string, p *tmproto.Proposal) []byte {
|
||||
pb := CanonicalizeProposal(chainID, p)
|
||||
bz, err := proto.Marshal(&pb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -100,7 +104,7 @@ func (p *Proposal) SignBytes(chainID string) []byte {
|
||||
// ToProto converts Proposal to protobuf
|
||||
func (p *Proposal) ToProto() *tmproto.Proposal {
|
||||
if p == nil {
|
||||
return nil
|
||||
return &tmproto.Proposal{}
|
||||
}
|
||||
pb := new(tmproto.Proposal)
|
||||
|
||||
|
||||
@@ -5,14 +5,19 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
tmproto "github.com/tendermint/tendermint/proto/types"
|
||||
)
|
||||
|
||||
var testProposal *Proposal
|
||||
var (
|
||||
testProposal *Proposal
|
||||
pbp *tmproto.Proposal
|
||||
)
|
||||
|
||||
func init() {
|
||||
var stamp, err = time.Parse(TimeFormat, "2018-02-11T07:09:22.765Z")
|
||||
@@ -26,13 +31,14 @@ func init() {
|
||||
POLRound: -1,
|
||||
Timestamp: stamp,
|
||||
}
|
||||
pbp = testProposal.ToProto()
|
||||
}
|
||||
|
||||
func TestProposalSignable(t *testing.T) {
|
||||
chainID := "test_chain_id"
|
||||
signBytes := testProposal.SignBytes(chainID)
|
||||
|
||||
expected, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeProposal(chainID, testProposal))
|
||||
signBytes := ProposalSignBytes(chainID, pbp)
|
||||
pb := CanonicalizeProposal(chainID, pbp)
|
||||
expected, err := proto.Marshal(&pb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Proposal")
|
||||
}
|
||||
@@ -52,41 +58,49 @@ func TestProposalVerifySignature(t *testing.T) {
|
||||
|
||||
prop := NewProposal(
|
||||
4, 2, 2,
|
||||
BlockID{[]byte{1, 2, 3}, PartSetHeader{777, []byte("proper")}})
|
||||
signBytes := prop.SignBytes("test_chain_id")
|
||||
BlockID{tmrand.Bytes(tmhash.Size), PartSetHeader{777, tmrand.Bytes(tmhash.Size)}})
|
||||
p := prop.ToProto()
|
||||
signBytes := ProposalSignBytes("test_chain_id", p)
|
||||
|
||||
// sign it
|
||||
err = privVal.SignProposal("test_chain_id", prop)
|
||||
err = privVal.SignProposal("test_chain_id", p)
|
||||
require.NoError(t, err)
|
||||
prop.Signature = p.Signature
|
||||
|
||||
// verify the same proposal
|
||||
valid := pubKey.VerifyBytes(signBytes, prop.Signature)
|
||||
require.True(t, valid)
|
||||
|
||||
// serialize, deserialize and verify again....
|
||||
newProp := new(Proposal)
|
||||
bs, err := cdc.MarshalBinaryLengthPrefixed(prop)
|
||||
newProp := new(tmproto.Proposal)
|
||||
pb := prop.ToProto()
|
||||
|
||||
bs, err := proto.Marshal(pb)
|
||||
require.NoError(t, err)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bs, &newProp)
|
||||
|
||||
err = proto.Unmarshal(bs, newProp)
|
||||
require.NoError(t, err)
|
||||
|
||||
np, err := ProposalFromProto(newProp)
|
||||
require.NoError(t, err)
|
||||
|
||||
// verify the transmitted proposal
|
||||
newSignBytes := newProp.SignBytes("test_chain_id")
|
||||
newSignBytes := ProposalSignBytes("test_chain_id", pb)
|
||||
require.Equal(t, string(signBytes), string(newSignBytes))
|
||||
valid = pubKey.VerifyBytes(newSignBytes, newProp.Signature)
|
||||
valid = pubKey.VerifyBytes(newSignBytes, np.Signature)
|
||||
require.True(t, valid)
|
||||
}
|
||||
|
||||
func BenchmarkProposalWriteSignBytes(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
testProposal.SignBytes("test_chain_id")
|
||||
ProposalSignBytes("test_chain_id", pbp)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProposalSign(b *testing.B) {
|
||||
privVal := NewMockPV()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := privVal.SignProposal("test_chain_id", testProposal)
|
||||
err := privVal.SignProposal("test_chain_id", pbp)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
@@ -95,13 +109,13 @@ func BenchmarkProposalSign(b *testing.B) {
|
||||
|
||||
func BenchmarkProposalVerifySignature(b *testing.B) {
|
||||
privVal := NewMockPV()
|
||||
err := privVal.SignProposal("test_chain_id", testProposal)
|
||||
err := privVal.SignProposal("test_chain_id", pbp)
|
||||
require.NoError(b, err)
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(b, err)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
pubKey.VerifyBytes(testProposal.SignBytes("test_chain_id"), testProposal.Signature)
|
||||
pubKey.VerifyBytes(ProposalSignBytes("test_chain_id", pbp), testProposal.Signature)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +150,9 @@ func TestProposalValidateBasic(t *testing.T) {
|
||||
prop := NewProposal(
|
||||
4, 2, 2,
|
||||
blockID)
|
||||
err := privVal.SignProposal("test_chain_id", prop)
|
||||
p := prop.ToProto()
|
||||
err := privVal.SignProposal("test_chain_id", p)
|
||||
prop.Signature = p.Signature
|
||||
require.NoError(t, err)
|
||||
tc.malleateProposal(prop)
|
||||
assert.Equal(t, tc.expectErr, prop.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
||||
|
||||
@@ -36,10 +36,12 @@ func MakeCommit(blockID BlockID, height int64, round int32,
|
||||
}
|
||||
|
||||
func signAddVote(privVal PrivValidator, vote *Vote, voteSet *VoteSet) (signed bool, err error) {
|
||||
err = privVal.SignVote(voteSet.ChainID(), vote)
|
||||
v := vote.ToProto()
|
||||
err = privVal.SignVote(voteSet.ChainID(), v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
vote.Signature = v.Signature
|
||||
return voteSet.AddVote(vote)
|
||||
}
|
||||
|
||||
@@ -66,9 +68,14 @@ func MakeVote(
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: blockID,
|
||||
}
|
||||
if err := privVal.SignVote(chainID, vote); err != nil {
|
||||
v := vote.ToProto()
|
||||
|
||||
if err := privVal.SignVote(chainID, v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vote.Signature = v.Signature
|
||||
|
||||
return vote, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -667,7 +667,9 @@ func TestValidatorSetVerifyCommit(t *testing.T) {
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: blockID,
|
||||
}
|
||||
sig, err := privKey.Sign(vote.SignBytes(chainID))
|
||||
|
||||
v := vote.ToProto()
|
||||
sig, err := privKey.Sign(VoteSignBytes(chainID, v))
|
||||
assert.NoError(t, err)
|
||||
vote.Signature = sig
|
||||
commit := NewCommit(vote.Height, vote.Round, blockID, []CommitSig{vote.CommitSig()})
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
tmproto "github.com/tendermint/tendermint/proto/types"
|
||||
@@ -13,7 +15,7 @@ import (
|
||||
|
||||
const (
|
||||
// MaxVoteBytes is a maximum vote size (including amino overhead).
|
||||
MaxVoteBytes int64 = 211
|
||||
MaxVoteBytes int64 = 209
|
||||
nilVoteStr string = "nil-Vote"
|
||||
)
|
||||
|
||||
@@ -81,8 +83,11 @@ func (vote *Vote) CommitSig() CommitSig {
|
||||
}
|
||||
}
|
||||
|
||||
func (vote *Vote) SignBytes(chainID string) []byte {
|
||||
bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainID, vote))
|
||||
//VoteSignBytes take the chainID & a vote, represented in protobuf, and creates a signature.
|
||||
// If any error arises this will panic
|
||||
func VoteSignBytes(chainID string, vote *tmproto.Vote) []byte {
|
||||
pb := CanonicalizeVote(chainID, vote)
|
||||
bz, err := proto.Marshal(&pb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -126,8 +131,8 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
|
||||
return ErrVoteInvalidValidatorAddress
|
||||
}
|
||||
|
||||
if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
|
||||
v := vote.ToProto()
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, v), vote.Signature) {
|
||||
return ErrVoteInvalidSignature
|
||||
}
|
||||
return nil
|
||||
@@ -152,11 +157,13 @@ func (vote *Vote) ValidateBasic() error {
|
||||
if err := vote.BlockID.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("wrong BlockID: %v", err)
|
||||
}
|
||||
|
||||
// BlockID.ValidateBasic would not err if we for instance have an empty hash but a
|
||||
// non-empty PartsSetHeader:
|
||||
if !vote.BlockID.IsZero() && !vote.BlockID.IsComplete() {
|
||||
return fmt.Errorf("blockID must be either empty or complete, got: %v", vote.BlockID)
|
||||
}
|
||||
|
||||
if len(vote.ValidatorAddress) != crypto.AddressSize {
|
||||
return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes",
|
||||
crypto.AddressSize,
|
||||
@@ -169,9 +176,11 @@ func (vote *Vote) ValidateBasic() error {
|
||||
if len(vote.Signature) == 0 {
|
||||
return errors.New("signature is missing")
|
||||
}
|
||||
|
||||
if len(vote.Signature) > MaxSignatureSize {
|
||||
return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -47,9 +48,11 @@ func exampleVote(t byte) *Vote {
|
||||
|
||||
func TestVoteSignable(t *testing.T) {
|
||||
vote := examplePrecommit()
|
||||
signBytes := vote.SignBytes("test_chain_id")
|
||||
v := vote.ToProto()
|
||||
signBytes := VoteSignBytes("test_chain_id", v)
|
||||
pb := CanonicalizeVote("test_chain_id", v)
|
||||
|
||||
expected, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote("test_chain_id", vote))
|
||||
expected, err := proto.Marshal(&pb)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Vote.")
|
||||
@@ -65,79 +68,47 @@ func TestVoteSignBytesTestVectors(t *testing.T) {
|
||||
0: {
|
||||
"", &Vote{},
|
||||
// NOTE: Height and Round are skipped here. This case needs to be considered while parsing.
|
||||
[]byte{0xd, 0x2a, 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
[]byte{0x2a, 0x2, 0x12, 0x0, 0x32, 0xb, 0x8, 0x80, 0x92, 0xb8,
|
||||
0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
},
|
||||
// with proper (fixed size) height and round (PreCommit):
|
||||
1: {
|
||||
"", &Vote{Height: 1, Round: 1, Type: tmproto.PrecommitType},
|
||||
[]byte{
|
||||
0x21, // length
|
||||
0x8, // (field_number << 3) | wire_type
|
||||
0x2, // PrecommitType
|
||||
0x11, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||
0x19, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||
0x2a, // (field_number << 3) | wire_type
|
||||
// remaining fields (timestamp):
|
||||
[]byte{0x8, 0x2, 0x10, 0x1, 0x18, 0x1, 0x2a, 0x2, 0x12, 0x0, 0x32,
|
||||
0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
},
|
||||
// with proper (fixed size) height and round (PreVote):
|
||||
2: {
|
||||
"", &Vote{Height: 1, Round: 1, Type: tmproto.PrevoteType},
|
||||
[]byte{
|
||||
0x21, // length
|
||||
0x8, // (field_number << 3) | wire_type
|
||||
0x1, // PrevoteType
|
||||
0x11, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||
0x19, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||
0x2a, // (field_number << 3) | wire_type
|
||||
// remaining fields (timestamp):
|
||||
0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
[]byte{0x8, 0x1, 0x10, 0x1, 0x18, 0x1, 0x2a, 0x2, 0x12, 0x0,
|
||||
0x32, 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
},
|
||||
3: {
|
||||
"", &Vote{Height: 1, Round: 1},
|
||||
[]byte{
|
||||
0x1f, // length
|
||||
0x11, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||
0x19, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||
// remaining fields (timestamp):
|
||||
0x2a,
|
||||
0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
[]byte{0x10, 0x1, 0x18, 0x1, 0x2a, 0x2, 0x12, 0x0, 0x32, 0xb,
|
||||
0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
|
||||
},
|
||||
// containing non-empty chain_id:
|
||||
4: {
|
||||
"test_chain_id", &Vote{Height: 1, Round: 1},
|
||||
[]byte{
|
||||
0x2e, // length
|
||||
0x11, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||
0x19, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||
// remaining fields:
|
||||
0x2a, // (field_number << 3) | wire_type
|
||||
0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1, // timestamp
|
||||
// (field_number << 3) | wire_type
|
||||
0x32,
|
||||
0xd, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64}, // chainID
|
||||
[]byte{0x10, 0x1, 0x18, 0x1, 0x2a, 0x2, 0x12, 0x0, 0x32, 0xb, 0x8,
|
||||
0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1, 0x3a, 0xd,
|
||||
0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64},
|
||||
},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
got := tc.vote.SignBytes(tc.chainID)
|
||||
v := tc.vote.ToProto()
|
||||
got := VoteSignBytes(tc.chainID, v)
|
||||
require.Equal(t, tc.want, got, "test case #%v: got unexpected sign bytes for Vote.", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteProposalNotEq(t *testing.T) {
|
||||
cv := CanonicalizeVote("", &Vote{Height: 1, Round: 1})
|
||||
p := CanonicalizeProposal("", &Proposal{Height: 1, Round: 1})
|
||||
vb, err := cdc.MarshalBinaryLengthPrefixed(cv)
|
||||
cv := CanonicalizeVote("", &tmproto.Vote{Height: 1, Round: 1})
|
||||
p := CanonicalizeProposal("", &tmproto.Proposal{Height: 1, Round: 1})
|
||||
vb, err := proto.Marshal(&cv)
|
||||
require.NoError(t, err)
|
||||
pb, err := cdc.MarshalBinaryLengthPrefixed(p)
|
||||
pb, err := proto.Marshal(&p)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, vb, pb)
|
||||
}
|
||||
@@ -148,25 +119,26 @@ func TestVoteVerifySignature(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
vote := examplePrecommit()
|
||||
signBytes := vote.SignBytes("test_chain_id")
|
||||
v := vote.ToProto()
|
||||
signBytes := VoteSignBytes("test_chain_id", v)
|
||||
|
||||
// sign it
|
||||
err = privVal.SignVote("test_chain_id", vote)
|
||||
err = privVal.SignVote("test_chain_id", v)
|
||||
require.NoError(t, err)
|
||||
|
||||
// verify the same vote
|
||||
valid := pubkey.VerifyBytes(vote.SignBytes("test_chain_id"), vote.Signature)
|
||||
valid := pubkey.VerifyBytes(VoteSignBytes("test_chain_id", v), v.Signature)
|
||||
require.True(t, valid)
|
||||
|
||||
// serialize, deserialize and verify again....
|
||||
precommit := new(Vote)
|
||||
bs, err := cdc.MarshalBinaryLengthPrefixed(vote)
|
||||
precommit := new(tmproto.Vote)
|
||||
bs, err := proto.Marshal(v)
|
||||
require.NoError(t, err)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bs, &precommit)
|
||||
err = proto.Unmarshal(bs, precommit)
|
||||
require.NoError(t, err)
|
||||
|
||||
// verify the transmitted vote
|
||||
newSignBytes := precommit.SignBytes("test_chain_id")
|
||||
newSignBytes := VoteSignBytes("test_chain_id", precommit)
|
||||
require.Equal(t, string(signBytes), string(newSignBytes))
|
||||
valid = pubkey.VerifyBytes(newSignBytes, precommit.Signature)
|
||||
require.True(t, valid)
|
||||
@@ -233,11 +205,12 @@ func TestMaxVoteBytes(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
v := vote.ToProto()
|
||||
privVal := NewMockPV()
|
||||
err := privVal.SignVote("test_chain_id", vote)
|
||||
err := privVal.SignVote("test_chain_id", v)
|
||||
require.NoError(t, err)
|
||||
|
||||
bz, err := cdc.MarshalBinaryLengthPrefixed(vote)
|
||||
bz, err := proto.Marshal(v)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, MaxVoteBytes, len(bz))
|
||||
@@ -245,13 +218,13 @@ func TestMaxVoteBytes(t *testing.T) {
|
||||
|
||||
func TestVoteString(t *testing.T) {
|
||||
str := examplePrecommit().String()
|
||||
expected := `Vote{56789:6AF1F4111082 12345/02/2(Precommit) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}`
|
||||
expected := `Vote{56789:6AF1F4111082 12345/02/PRECOMMIT_TYPE(Precommit) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
if str != expected {
|
||||
t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str)
|
||||
}
|
||||
|
||||
str2 := examplePrevote().String()
|
||||
expected = `Vote{56789:6AF1F4111082 12345/02/1(Prevote) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}`
|
||||
expected = `Vote{56789:6AF1F4111082 12345/02/PREVOTE_TYPE(Prevote) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
if str2 != expected {
|
||||
t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str2)
|
||||
}
|
||||
@@ -280,7 +253,9 @@ func TestVoteValidateBasic(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
vote := examplePrecommit()
|
||||
err := privVal.SignVote("test_chain_id", vote)
|
||||
v := vote.ToProto()
|
||||
err := privVal.SignVote("test_chain_id", v)
|
||||
vote.Signature = v.Signature
|
||||
require.NoError(t, err)
|
||||
tc.malleateVote(vote)
|
||||
assert.Equal(t, tc.expectErr, vote.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
||||
@@ -291,7 +266,9 @@ func TestVoteValidateBasic(t *testing.T) {
|
||||
func TestVoteProtobuf(t *testing.T) {
|
||||
privVal := NewMockPV()
|
||||
vote := examplePrecommit()
|
||||
err := privVal.SignVote("test_chain_id", vote)
|
||||
v := vote.ToProto()
|
||||
err := privVal.SignVote("test_chain_id", v)
|
||||
vote.Signature = v.Signature
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
|
||||
Reference in New Issue
Block a user