From ed42f70248abea41bf68a099fb94346f2f4ac1e1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 17 Dec 2016 13:57:37 -0500 Subject: [PATCH 1/3] types: benchmark WriteSignBytes --- types/proposal_test.go | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/types/proposal_test.go b/types/proposal_test.go index 1d8c62051..332da4fbc 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -4,14 +4,15 @@ import ( "testing" ) +var testProposal = &Proposal{ + Height: 12345, + Round: 23456, + BlockPartsHeader: PartSetHeader{111, []byte("blockparts")}, + POLRound: -1, +} + func TestProposalSignable(t *testing.T) { - proposal := &Proposal{ - Height: 12345, - Round: 23456, - BlockPartsHeader: PartSetHeader{111, []byte("blockparts")}, - POLRound: -1, - } - signBytes := SignBytes("test_chain_id", proposal) + signBytes := SignBytes("test_chain_id", testProposal) signStr := string(signBytes) expected := `{"chain_id":"test_chain_id","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_block_id":null,"pol_round":-1,"round":23456}}` @@ -19,3 +20,27 @@ func TestProposalSignable(t *testing.T) { t.Errorf("Got unexpected sign string for Proposal. Expected:\n%v\nGot:\n%v", expected, signStr) } } + +func BenchmarkProposalWriteSignBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + SignBytes("test_chain_id", testProposal) + } +} + +func BenchmarkProposalSign(b *testing.B) { + privVal := GenPrivValidator() + for i := 0; i < b.N; i++ { + privVal.Sign(SignBytes("test_chain_id", testProposal)) + } +} + +func BenchmarkProposalVerifySignature(b *testing.B) { + signBytes := SignBytes("test_chain_id", testProposal) + privVal := GenPrivValidator() + signature := privVal.Sign(signBytes) + pubKey := privVal.PubKey + + for i := 0; i < b.N; i++ { + pubKey.VerifyBytes(SignBytes("test_chain_id", testProposal), signature) + } +} From da8b04361296c5dc52f8e61eaab8f63af0fb807a Mon Sep 17 00:00:00 2001 From: zachary balder Date: Wed, 16 Nov 2016 17:20:44 -0600 Subject: [PATCH 2/3] sign bytes w struct literals --- types/part_set.go | 10 +++++++++- types/proposal.go | 49 +++++++++++++++++++++++++++++++++-------------- types/vote.go | 38 ++++++++++++++++++++++++++++++++---- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/types/part_set.go b/types/part_set.go index f132c5fe6..ade421450 100644 --- a/types/part_set.go +++ b/types/part_set.go @@ -74,7 +74,15 @@ func (psh PartSetHeader) Equals(other PartSetHeader) bool { } func (psh PartSetHeader) WriteSignBytes(w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"hash":"%X","total":%v}`, psh.Hash, psh.Total)), w, n, err) + wire.WriteJSON( + struct { + Hash []byte `json:"hash"` + Total int `json:"total"` + }{ + psh.Hash, + psh.Total, + }, + w, n, err) } //------------------------------------- diff --git a/types/proposal.go b/types/proposal.go index 85ac5f061..91e53038f 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -5,7 +5,7 @@ import ( "fmt" "io" - . "github.com/tendermint/go-common" + //. "github.com/tendermint/go-common" "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" ) @@ -16,12 +16,12 @@ var ( ) type Proposal struct { - Height int `json:"height"` - Round int `json:"round"` - BlockPartsHeader PartSetHeader `json:"block_parts_header"` - POLRound int `json:"pol_round"` // -1 if null. - POLBlockID BlockID `json:"pol_block_id"` // zero if null. - Signature crypto.SignatureEd25519 `json:"signature"` + Height int `json:"height"` + Round int `json:"round"` + BlockPartsHeader PartSetHeader `json:"block_parts_header"` + POLRound int `json:"pol_round"` // -1 if null. + POLBlockID BlockID `json:"pol_block_id"` // zero if null. + Signature crypto.Signature `json:"signature"` } // polRound: -1 if no polRound. @@ -41,11 +41,32 @@ func (p *Proposal) String() string { } func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err) - wire.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err) - p.BlockPartsHeader.WriteSignBytes(w, n, err) - wire.WriteTo([]byte(Fmt(`,"height":%v,"pol_block_id":`, p.Height)), w, n, err) - p.POLBlockID.WriteSignBytes(w, n, err) - wire.WriteTo([]byte(Fmt(`,"pol_round":%v`, p.POLRound)), w, n, err) - wire.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err) + + wire.WriteJSON( + struct { + ChainID string `json:"chain_id"` + Proposal struct { + BlockPartsHeader PartSetHeader `json:"block_parts_header"` + Height int `json:"height"` + POLBlockID BlockID `json:"pol_block_id"` + POLRound int `json:"pol_round"` + Round int `json:"round"` + } `json:"proposal"` + }{ + chainID, + struct { + BlockPartsHeader PartSetHeader `json:"block_parts_header"` + Height int `json:"height"` + POLBlockID BlockID `json:"pol_block_id"` + POLRound int `json:"pol_round"` + Round int `json:"round"` + }{ + p.BlockPartsHeader, + p.Height, + p.POLBlockID, + p.POLRound, + p.Round, + }, + }, + w, n, err) } diff --git a/types/vote.go b/types/vote.go index 92d99f485..e95008639 100644 --- a/types/vote.go +++ b/types/vote.go @@ -57,10 +57,40 @@ type Vote struct { } func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err) - wire.WriteTo([]byte(`,"vote":{"block_id":`), w, n, err) - vote.BlockID.WriteSignBytes(w, n, err) - wire.WriteTo([]byte(Fmt(`,"height":%v,"round":%v,"type":%v}}`, vote.Height, vote.Round, vote.Type)), w, n, err) + + wire.WriteJSON( + struct { + ChainID string `json:"chain_id"` + Vote struct { + BlockID BlockID `json:"block_id"` + Height int `json:"height"` + Round int `json:"round"` + Signature crypto.Signature `json:"signature"` + Type byte `json:"type"` + ValidatorAddress []byte `json:"validator_address"` + ValidatorIndex int `json:"validator_index"` + } `json: "vote"` + }{ + chainID, + struct { + BlockID BlockID `json:"block_id"` + Height int `json:"height"` + Round int `json:"round"` + Signature crypto.Signature `json:"signature"` + Type byte `json:"type"` + ValidatorAddress []byte `json:"validator_address"` + ValidatorIndex int `json:"validator_index"` + }{ + vote.BlockID, + vote.Height, + vote.Round, + vote.Signature, + vote.Type, + vote.ValidatorAddress, + vote.ValidatorIndex, + }, + }, + w, n, err) } func (vote *Vote) Copy() *Vote { From 1b3766d8027339223b48433fa7df0826a112dd2e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 2 Dec 2016 05:01:47 -0500 Subject: [PATCH 3/3] types: canonical_json.go --- types/block.go | 5 ++- types/canonical_json.go | 77 +++++++++++++++++++++++++++++++++++++++++ types/part_set.go | 10 +----- types/proposal.go | 32 +++-------------- types/proposal_test.go | 2 +- types/vote.go | 38 +++----------------- types/vote_set_test.go | 5 ++- 7 files changed, 93 insertions(+), 76 deletions(-) create mode 100644 types/canonical_json.go diff --git a/types/block.go b/types/block.go index d971b90b6..a19afaac5 100644 --- a/types/block.go +++ b/types/block.go @@ -409,10 +409,9 @@ func (blockID BlockID) WriteSignBytes(w io.Writer, n *int, err *error) { if blockID.IsZero() { wire.WriteTo([]byte("null"), w, n, err) } else { - wire.WriteTo([]byte(Fmt(`{"hash":"%X","parts":`, blockID.Hash)), w, n, err) - blockID.PartsHeader.WriteSignBytes(w, n, err) - wire.WriteTo([]byte("}"), w, n, err) + wire.WriteJSON(CanonicalBlockID(blockID), w, n, err) } + } func (blockID BlockID) String() string { diff --git a/types/canonical_json.go b/types/canonical_json.go new file mode 100644 index 000000000..68dd6924c --- /dev/null +++ b/types/canonical_json.go @@ -0,0 +1,77 @@ +package types + +// canonical json is go-wire's json for structs with fields in alphabetical order + +type CanonicalJSONBlockID struct { + Hash []byte `json:"hash,omitempty"` + PartsHeader CanonicalJSONPartSetHeader `json:"parts,omitempty"` +} + +type CanonicalJSONPartSetHeader struct { + Hash []byte `json:"hash"` + Total int `json:"total"` +} + +type CanonicalJSONProposal struct { + BlockPartsHeader CanonicalJSONPartSetHeader `json:"block_parts_header"` + Height int `json:"height"` + POLBlockID CanonicalJSONBlockID `json:"pol_block_id"` + POLRound int `json:"pol_round"` + Round int `json:"round"` +} + +type CanonicalJSONVote struct { + BlockID CanonicalJSONBlockID `json:"block_id"` + Height int `json:"height"` + Round int `json:"round"` + Type byte `json:"type"` +} + +//------------------------------------ +// Messages including a "chain id" can only be applied to one chain, hence "Once" + +type CanonicalJSONOnceProposal struct { + ChainID string `json:"chain_id"` + Proposal CanonicalJSONProposal `json:"proposal"` +} + +type CanonicalJSONOnceVote struct { + ChainID string `json:"chain_id"` + Vote CanonicalJSONVote `json:"vote"` +} + +//----------------------------------- +// Canonicalize the structs + +func CanonicalBlockID(blockID BlockID) CanonicalJSONBlockID { + return CanonicalJSONBlockID{ + Hash: blockID.Hash, + PartsHeader: CanonicalPartSetHeader(blockID.PartsHeader), + } +} + +func CanonicalPartSetHeader(psh PartSetHeader) CanonicalJSONPartSetHeader { + return CanonicalJSONPartSetHeader{ + psh.Hash, + psh.Total, + } +} + +func CanonicalProposal(proposal *Proposal) CanonicalJSONProposal { + return CanonicalJSONProposal{ + BlockPartsHeader: CanonicalPartSetHeader(proposal.BlockPartsHeader), + Height: proposal.Height, + POLBlockID: CanonicalBlockID(proposal.POLBlockID), + POLRound: proposal.POLRound, + Round: proposal.Round, + } +} + +func CanonicalVote(vote *Vote) CanonicalJSONVote { + return CanonicalJSONVote{ + CanonicalBlockID(vote.BlockID), + vote.Height, + vote.Round, + vote.Type, + } +} diff --git a/types/part_set.go b/types/part_set.go index ade421450..c21524405 100644 --- a/types/part_set.go +++ b/types/part_set.go @@ -74,15 +74,7 @@ func (psh PartSetHeader) Equals(other PartSetHeader) bool { } func (psh PartSetHeader) WriteSignBytes(w io.Writer, n *int, err *error) { - wire.WriteJSON( - struct { - Hash []byte `json:"hash"` - Total int `json:"total"` - }{ - psh.Hash, - psh.Total, - }, - w, n, err) + wire.WriteJSON(CanonicalPartSetHeader(psh), w, n, err) } //------------------------------------- diff --git a/types/proposal.go b/types/proposal.go index 91e53038f..9852011f3 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -41,32 +41,8 @@ func (p *Proposal) String() string { } func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - - wire.WriteJSON( - struct { - ChainID string `json:"chain_id"` - Proposal struct { - BlockPartsHeader PartSetHeader `json:"block_parts_header"` - Height int `json:"height"` - POLBlockID BlockID `json:"pol_block_id"` - POLRound int `json:"pol_round"` - Round int `json:"round"` - } `json:"proposal"` - }{ - chainID, - struct { - BlockPartsHeader PartSetHeader `json:"block_parts_header"` - Height int `json:"height"` - POLBlockID BlockID `json:"pol_block_id"` - POLRound int `json:"pol_round"` - Round int `json:"round"` - }{ - p.BlockPartsHeader, - p.Height, - p.POLBlockID, - p.POLRound, - p.Round, - }, - }, - w, n, err) + wire.WriteJSON(CanonicalJSONOnceProposal{ + ChainID: chainID, + Proposal: CanonicalProposal(p), + }, w, n, err) } diff --git a/types/proposal_test.go b/types/proposal_test.go index 332da4fbc..622236b60 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -15,7 +15,7 @@ func TestProposalSignable(t *testing.T) { signBytes := SignBytes("test_chain_id", testProposal) signStr := string(signBytes) - expected := `{"chain_id":"test_chain_id","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_block_id":null,"pol_round":-1,"round":23456}}` + expected := `{"chain_id":"test_chain_id","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_block_id":{},"pol_round":-1,"round":23456}}` if signStr != expected { t.Errorf("Got unexpected sign string for Proposal. Expected:\n%v\nGot:\n%v", expected, signStr) } diff --git a/types/vote.go b/types/vote.go index e95008639..2a30da0ce 100644 --- a/types/vote.go +++ b/types/vote.go @@ -57,40 +57,10 @@ type Vote struct { } func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - - wire.WriteJSON( - struct { - ChainID string `json:"chain_id"` - Vote struct { - BlockID BlockID `json:"block_id"` - Height int `json:"height"` - Round int `json:"round"` - Signature crypto.Signature `json:"signature"` - Type byte `json:"type"` - ValidatorAddress []byte `json:"validator_address"` - ValidatorIndex int `json:"validator_index"` - } `json: "vote"` - }{ - chainID, - struct { - BlockID BlockID `json:"block_id"` - Height int `json:"height"` - Round int `json:"round"` - Signature crypto.Signature `json:"signature"` - Type byte `json:"type"` - ValidatorAddress []byte `json:"validator_address"` - ValidatorIndex int `json:"validator_index"` - }{ - vote.BlockID, - vote.Height, - vote.Round, - vote.Signature, - vote.Type, - vote.ValidatorAddress, - vote.ValidatorIndex, - }, - }, - w, n, err) + wire.WriteJSON(CanonicalJSONOnceVote{ + chainID, + CanonicalVote(vote), + }, w, n, err) } func (vote *Vote) Copy() *Vote { diff --git a/types/vote_set_test.go b/types/vote_set_test.go index 19523a825..48ccb0b1f 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -92,7 +92,10 @@ func TestAddVote(t *testing.T) { Type: VoteTypePrevote, BlockID: BlockID{nil, PartSetHeader{}}, } - signAddVote(val0, vote, voteSet) + _, err := signAddVote(val0, vote, voteSet) + if err != nil { + t.Error(err) + } if voteSet.GetByAddress(val0.Address) == nil { t.Errorf("Expected GetByAddress(val0.Address) to be present")