diff --git a/types/block.go b/types/block.go index 4c91c5fe1..461782fd8 100644 --- a/types/block.go +++ b/types/block.go @@ -420,7 +420,7 @@ func (data *Data) StringIndented(indent string) string { // BlockID defines the unique ID of a block as its Hash and its PartSetHeader type BlockID struct { - Hash data.Bytes `json:"hash"` + Hash data.Bytes `json:"hash,omitempty"` PartsHeader PartSetHeader `json:"parts"` } diff --git a/types/canonical_json.go b/types/canonical_json.go index a2e91164f..be371f242 100644 --- a/types/canonical_json.go +++ b/types/canonical_json.go @@ -22,6 +22,7 @@ type CanonicalJSONProposal struct { POLBlockID CanonicalJSONBlockID `json:"pol_block_id"` POLRound int `json:"pol_round"` Round int `json:"round"` + Timestamp string `json:"timestamp"` } type CanonicalJSONVote struct { @@ -78,6 +79,7 @@ func CanonicalProposal(proposal *Proposal) CanonicalJSONProposal { return CanonicalJSONProposal{ BlockPartsHeader: CanonicalPartSetHeader(proposal.BlockPartsHeader), Height: proposal.Height, + Timestamp: proposal.TimeString(), POLBlockID: CanonicalBlockID(proposal.POLBlockID), POLRound: proposal.POLRound, Round: proposal.Round, diff --git a/types/proposal.go b/types/proposal.go index 93e788961..58dfa0944 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "time" "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" @@ -14,6 +15,9 @@ var ( ErrInvalidBlockPartHash = errors.New("Error invalid block part hash") ) +// TimeFormat is RFC3339Millis, used for generating the sigs +const TimeFormat = "2006-01-02T15:04:05.999Z07:00" + // Proposal defines a block proposal for the consensus. // It refers to the block only by its PartSetHeader. // It must be signed by the correct proposer for the given Height/Round @@ -22,6 +26,7 @@ var ( type Proposal struct { Height int64 `json:"height"` Round int `json:"round"` + Timestamp time.Time `json:"timestamp"` BlockPartsHeader PartSetHeader `json:"block_parts_header"` POLRound int `json:"pol_round"` // -1 if null. POLBlockID BlockID `json:"pol_block_id"` // zero if null. @@ -34,16 +39,23 @@ func NewProposal(height int64, round int, blockPartsHeader PartSetHeader, polRou return &Proposal{ Height: height, Round: round, + Timestamp: time.Now().UTC(), BlockPartsHeader: blockPartsHeader, POLRound: polRound, POLBlockID: polBlockID, } } +// TimeString returns the canonical encoding of timestamp +func (p *Proposal) TimeString() string { + return p.Timestamp.Format(TimeFormat) +} + // String returns a string representation of the Proposal. func (p *Proposal) String() string { - return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %v}", p.Height, p.Round, - p.BlockPartsHeader, p.POLRound, p.POLBlockID, p.Signature) + return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %v @ %s}", + p.Height, p.Round, p.BlockPartsHeader, p.POLRound, + p.POLBlockID, p.Signature, p.TimeString()) } // WriteSignBytes writes the Proposal bytes for signing diff --git a/types/proposal_test.go b/types/proposal_test.go index 352ba8de1..c2e62f258 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -2,20 +2,30 @@ package types import ( "testing" + "time" ) -var testProposal = &Proposal{ - Height: 12345, - Round: 23456, - BlockPartsHeader: PartSetHeader{111, []byte("blockparts")}, - POLRound: -1, +var testProposal *Proposal + +func init() { + var stamp, err = time.Parse(TimeFormat, "2018-02-11T07:09:22.765Z") + if err != nil { + panic(err) + } + testProposal = &Proposal{ + Height: 12345, + Round: 23456, + BlockPartsHeader: PartSetHeader{111, []byte("blockparts")}, + POLRound: -1, + Timestamp: stamp, + } } 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":{},"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,"timestamp":"2018-02-11T07:09:22.765Z"}}` if signStr != expected { t.Errorf("Got unexpected sign string for Proposal. Expected:\n%v\nGot:\n%v", expected, signStr) }