WIP: get a feel for what changes will be necessary and where to put the

new Response / Request types
This commit is contained in:
Ismail Khoffi
2018-09-19 19:34:08 +02:00
parent aa5495f24e
commit 6ddc0199ef
7 changed files with 49 additions and 42 deletions

View File

@@ -83,18 +83,6 @@ func CanonicalProposal(chainID string, proposal *Proposal) CanonicalJSONProposal
}
}
func CanonicalVote(chainID string, vote *Vote) CanonicalJSONVote {
return CanonicalJSONVote{
ChainID: chainID,
Type: "vote",
BlockID: CanonicalBlockID(vote.BlockID),
Height: vote.Height,
Round: vote.Round,
Timestamp: CanonicalTime(vote.Timestamp),
VoteType: vote.Type,
}
}
func CanonicalHeartbeat(chainID string, heartbeat *Heartbeat) CanonicalJSONHeartbeat {
return CanonicalJSONHeartbeat{
ChainID: chainID,

View File

@@ -4,7 +4,7 @@ import (
"bytes"
"fmt"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/merkle"
@@ -62,8 +62,9 @@ func MaxEvidenceBytesPerBlock(blockMaxBytes int) int {
// DuplicateVoteEvidence contains evidence a validator signed two conflicting votes.
type DuplicateVoteEvidence struct {
PubKey crypto.PubKey
VoteA *Vote
VoteB *Vote
// TODO(ismail): this probably need to be `SignedVoteReply`s
VoteA *SignVoteReply
VoteB *SignVoteReply
}
// String returns a string representation of the evidence.
@@ -74,7 +75,7 @@ func (dve *DuplicateVoteEvidence) String() string {
// Height returns the height this evidence refers to.
func (dve *DuplicateVoteEvidence) Height() int64 {
return dve.VoteA.Height
return dve.VoteA.Vote.Height
}
// Address returns the address of the validator.
@@ -91,39 +92,39 @@ func (dve *DuplicateVoteEvidence) Hash() []byte {
// To be conflicting, they must be from the same validator, for the same H/R/S, but for different blocks.
func (dve *DuplicateVoteEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
// H/R/S must be the same
if dve.VoteA.Height != dve.VoteB.Height ||
dve.VoteA.Round != dve.VoteB.Round ||
dve.VoteA.Type != dve.VoteB.Type {
if dve.VoteA.Vote.Height != dve.VoteB.Vote.Height ||
dve.VoteA.Vote.Round != dve.VoteB.Vote.Round ||
dve.VoteA.Vote.Type != dve.VoteB.Vote.Type {
return fmt.Errorf("DuplicateVoteEvidence Error: H/R/S does not match. Got %v and %v", dve.VoteA, dve.VoteB)
}
// Address must be the same
if !bytes.Equal(dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) {
return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress)
if !bytes.Equal(dve.VoteA.Vote.ValidatorAddress, dve.VoteB.Vote.ValidatorAddress) {
return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.Vote.ValidatorAddress, dve.VoteB.Vote.ValidatorAddress)
}
// Index must be the same
if dve.VoteA.ValidatorIndex != dve.VoteB.ValidatorIndex {
return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.ValidatorIndex, dve.VoteB.ValidatorIndex)
if dve.VoteA.Vote.ValidatorIndex != dve.VoteB.Vote.ValidatorIndex {
return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.Vote.ValidatorIndex, dve.VoteB.Vote.ValidatorIndex)
}
// BlockIDs must be different
if dve.VoteA.BlockID.Equals(dve.VoteB.BlockID) {
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID)
if dve.VoteA.Vote.BlockID.Equals(dve.VoteB.Vote.BlockID) {
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.Vote.BlockID)
}
// pubkey must match address (this should already be true, sanity check)
addr := dve.VoteA.ValidatorAddress
addr := dve.VoteA.Vote.ValidatorAddress
if !bytes.Equal(pubKey.Address(), addr) {
return fmt.Errorf("DuplicateVoteEvidence FAILED SANITY CHECK - address (%X) doesn't match pubkey (%v - %X)",
addr, pubKey, pubKey.Address())
}
// Signatures must be valid
if !pubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
if !pubKey.VerifyBytes(dve.VoteA.Vote.SignBytes(), dve.VoteA.Signature) {
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature)
}
if !pubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
if !pubKey.VerifyBytes(dve.VoteB.Vote.SignBytes(), dve.VoteB.Signature) {
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature)
}

View File

@@ -14,7 +14,7 @@ type PrivValidator interface {
GetAddress() Address // redundant since .PubKey().Address()
GetPubKey() crypto.PubKey
SignVote(chainID string, vote *Vote) error
SignVote(vote *Vote) (SignVoteReply, error)
SignProposal(chainID string, proposal *Proposal) error
SignHeartbeat(chainID string, heartbeat *Heartbeat) error
}
@@ -62,14 +62,18 @@ func (pv *MockPV) GetPubKey() crypto.PubKey {
}
// Implements PrivValidator.
func (pv *MockPV) SignVote(chainID string, vote *Vote) error {
signBytes := vote.SignBytes(chainID)
func (pv *MockPV) SignVote(vote *Vote) (SignVoteReply, error) {
signBytes := vote.SignBytes()
sig, err := pv.privKey.Sign(signBytes)
if err != nil {
return err
// TODO(ismail): encapsulate error into reply!
return SignVoteReply{}, err
}
vote.Signature = sig
return nil
return SignVoteReply{
Vote: *vote,
Signature: sig,
}, nil
}
// Implements PrivValidator.

View File

@@ -3,9 +3,7 @@ package types
// Signable is an interface for all signable things.
// It typically removes signatures before serializing.
// SignBytes returns the bytes to be signed
// NOTE: chainIDs are part of the SignBytes but not
// necessarily the object themselves.
// NOTE: Expected to panic if there is an error marshalling.
type Signable interface {
SignBytes(chainID string) []byte
SignBytes() []byte
}

View File

@@ -31,7 +31,8 @@ func MakeCommit(blockID BlockID, height int64, round int,
}
func signAddVote(privVal PrivValidator, vote *Vote, voteSet *VoteSet) (signed bool, err error) {
err = privVal.SignVote(voteSet.ChainID(), vote)
vote.ChainID = voteSet.ChainID()
repl, err := privVal.SignVote(vote)
if err != nil {
return false, err
}

View File

@@ -287,7 +287,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i
}
_, val := vals.GetByIndex(idx)
// Validate signature.
precommitSignBytes := precommit.SignBytes(chainID)
precommitSignBytes := precommit.SignBytes()
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
}

View File

@@ -73,11 +73,26 @@ type Vote struct {
Timestamp time.Time `json:"timestamp"`
Type byte `json:"type"`
BlockID BlockID `json:"block_id"` // zero if vote is nil.
Signature []byte `json:"signature"`
ChainID string `json:"chain_id"`
}
func (vote *Vote) SignBytes(chainID string) []byte {
bz, err := cdc.MarshalJSON(CanonicalVote(chainID, vote))
type SignVoteRequest struct {
Vote Vote
}
type SignVoteReply struct {
Vote Vote
Signature []byte
Err Error
}
type Error struct {
ErrCode uint16
Description string
}
func (vote *Vote) SignBytes() []byte {
bz, err := cdc.MarshalBinary(vote)
if err != nil {
panic(err)
}