Add Timestamp to Proposal for issue #929
Store it as time.Timestamp locally, encode it as RFC3339 with milliseconds before signing the canonical form.
This commit is contained in:
parent
5ecae52bf1
commit
7deda53b7c
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue