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