privval: migrate to protobuf (#4985)

This commit is contained in:
Marko
2020-06-11 11:54:02 +02:00
committed by GitHub
parent 31a361d119
commit f6243d8b9e
49 changed files with 3215 additions and 642 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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")

View File

@@ -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
}

View File

@@ -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()})

View File

@@ -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
}

View File

@@ -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 {