mirror of
https://github.com/fluencelabs/tendermint
synced 2025-08-01 04:31:57 +00:00
Fix proposal sign bytes. Start tracking blockID in POL
This commit is contained in:
@@ -71,7 +71,8 @@ func decideProposal(cs1 *ConsensusState, vs *validatorStub, height, round int) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make proposal
|
// Make proposal
|
||||||
proposal = types.NewProposal(height, round, blockParts.Header(), cs1.Votes.POLRound())
|
polRound, polBlockID := cs1.Votes.POLInfo()
|
||||||
|
proposal = types.NewProposal(height, round, blockParts.Header(), polRound, polBlockID)
|
||||||
if err := vs.SignProposal(config.GetString("chain_id"), proposal); err != nil {
|
if err := vs.SignProposal(config.GetString("chain_id"), proposal); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -133,17 +133,19 @@ func (hvs *HeightVoteSet) Precommits(round int) *types.VoteSet {
|
|||||||
return hvs.getVoteSet(round, types.VoteTypePrecommit)
|
return hvs.getVoteSet(round, types.VoteTypePrecommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last round that has +2/3 prevotes for a particular block or nil.
|
// Last round and blockID that has +2/3 prevotes for a particular block or nil.
|
||||||
// Returns -1 if no such round exists.
|
// Returns -1 if no such round exists.
|
||||||
func (hvs *HeightVoteSet) POLRound() int {
|
func (hvs *HeightVoteSet) POLInfo() (polRound int, polBlockID types.BlockID) {
|
||||||
hvs.mtx.Lock()
|
hvs.mtx.Lock()
|
||||||
defer hvs.mtx.Unlock()
|
defer hvs.mtx.Unlock()
|
||||||
for r := hvs.round; r >= 0; r-- {
|
for r := hvs.round; r >= 0; r-- {
|
||||||
if hvs.getVoteSet(r, types.VoteTypePrevote).HasTwoThirdsMajority() {
|
rvs := hvs.getVoteSet(r, types.VoteTypePrevote)
|
||||||
return r
|
polBlockID, ok := rvs.TwoThirdsMajority()
|
||||||
|
if ok {
|
||||||
|
return r, polBlockID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1, types.BlockID{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet {
|
func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet {
|
||||||
|
@@ -391,13 +391,13 @@ OUTER_LOOP:
|
|||||||
|
|
||||||
// Send Proposal && ProposalPOL BitArray?
|
// Send Proposal && ProposalPOL BitArray?
|
||||||
if rs.Proposal != nil && !prs.Proposal {
|
if rs.Proposal != nil && !prs.Proposal {
|
||||||
// Proposal
|
// Proposal: share the proposal metadata with peer.
|
||||||
{
|
{
|
||||||
msg := &ProposalMessage{Proposal: rs.Proposal}
|
msg := &ProposalMessage{Proposal: rs.Proposal}
|
||||||
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
|
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
|
||||||
ps.SetHasProposal(rs.Proposal)
|
ps.SetHasProposal(rs.Proposal)
|
||||||
}
|
}
|
||||||
// ProposalPOL.
|
// ProposalPOL: lets peer know which POL votes we have so far.
|
||||||
// Peer must receive ProposalMessage first.
|
// Peer must receive ProposalMessage first.
|
||||||
// rs.Proposal was validated, so rs.Proposal.POLRound <= rs.Round,
|
// rs.Proposal was validated, so rs.Proposal.POLRound <= rs.Round,
|
||||||
// so we definitely have rs.Votes.Prevotes(rs.Proposal.POLRound).
|
// so we definitely have rs.Votes.Prevotes(rs.Proposal.POLRound).
|
||||||
|
@@ -853,7 +853,8 @@ func (cs *ConsensusState) decideProposal(height, round int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make proposal
|
// Make proposal
|
||||||
proposal := types.NewProposal(height, round, blockParts.Header(), cs.Votes.POLRound())
|
polRound, polBlockID := cs.Votes.POLInfo()
|
||||||
|
proposal := types.NewProposal(height, round, blockParts.Header(), polRound, polBlockID)
|
||||||
err := cs.privValidator.SignProposal(cs.state.ChainID, proposal)
|
err := cs.privValidator.SignProposal(cs.state.ChainID, proposal)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Set fields
|
// Set fields
|
||||||
@@ -1064,8 +1065,9 @@ func (cs *ConsensusState) enterPrecommit(height int, round int) {
|
|||||||
types.FireEventPolka(cs.evsw, cs.RoundStateEvent())
|
types.FireEventPolka(cs.evsw, cs.RoundStateEvent())
|
||||||
|
|
||||||
// the latest POLRound should be this round
|
// the latest POLRound should be this round
|
||||||
if cs.Votes.POLRound() < round {
|
polRound, _ := cs.Votes.POLInfo()
|
||||||
PanicSanity(Fmt("This POLRound should be %v but got %", round, cs.Votes.POLRound()))
|
if polRound < round {
|
||||||
|
PanicSanity(Fmt("This POLRound should be %v but got %", round, polRound))
|
||||||
}
|
}
|
||||||
|
|
||||||
// +2/3 prevoted nil. Unlock and precommit nil.
|
// +2/3 prevoted nil. Unlock and precommit nil.
|
||||||
|
@@ -198,7 +198,7 @@ func TestBadProposal(t *testing.T) {
|
|||||||
stateHash[0] = byte((stateHash[0] + 1) % 255)
|
stateHash[0] = byte((stateHash[0] + 1) % 255)
|
||||||
propBlock.AppHash = stateHash
|
propBlock.AppHash = stateHash
|
||||||
propBlockParts := propBlock.MakePartSet()
|
propBlockParts := propBlock.MakePartSet()
|
||||||
proposal := types.NewProposal(vs2.Height, round, propBlockParts.Header(), -1)
|
proposal := types.NewProposal(vs2.Height, round, propBlockParts.Header(), -1, types.BlockID{})
|
||||||
if err := vs2.SignProposal(config.GetString("chain_id"), proposal); err != nil {
|
if err := vs2.SignProposal(config.GetString("chain_id"), proposal); err != nil {
|
||||||
t.Fatal("failed to sign bad proposal", err)
|
t.Fatal("failed to sign bad proposal", err)
|
||||||
}
|
}
|
||||||
@@ -832,6 +832,7 @@ func TestLockPOLSafety2(t *testing.T) {
|
|||||||
prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
|
prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
|
||||||
propBlockHash1 := propBlock1.Hash()
|
propBlockHash1 := propBlock1.Hash()
|
||||||
propBlockParts1 := propBlock1.MakePartSet()
|
propBlockParts1 := propBlock1.MakePartSet()
|
||||||
|
propBlockID1 := types.BlockID{propBlockHash1, propBlockParts1.Header()}
|
||||||
|
|
||||||
incrementRound(vs2, vs3, vs4)
|
incrementRound(vs2, vs3, vs4)
|
||||||
|
|
||||||
@@ -864,7 +865,7 @@ func TestLockPOLSafety2(t *testing.T) {
|
|||||||
<-timeoutWaitCh
|
<-timeoutWaitCh
|
||||||
|
|
||||||
// in round 2 we see the polkad block from round 0
|
// in round 2 we see the polkad block from round 0
|
||||||
newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0)
|
newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0, propBlockID1)
|
||||||
if err := vs3.SignProposal(config.GetString("chain_id"), newProp); err != nil {
|
if err := vs3.SignProposal(config.GetString("chain_id"), newProp); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@@ -376,9 +376,13 @@ func (blockID BlockID) Key() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (blockID BlockID) WriteSignBytes(w io.Writer, n *int, err *error) {
|
func (blockID BlockID) WriteSignBytes(w io.Writer, n *int, err *error) {
|
||||||
wire.WriteTo([]byte(Fmt(`{"hash":"%X","parts":`, blockID.Hash)), w, n, err)
|
if blockID.IsZero() {
|
||||||
blockID.PartsHeader.WriteSignBytes(w, n, err)
|
wire.WriteTo([]byte("null"), w, n, err)
|
||||||
wire.WriteTo([]byte("}"), 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (blockID BlockID) String() string {
|
func (blockID BlockID) String() string {
|
||||||
|
@@ -19,29 +19,33 @@ type Proposal struct {
|
|||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
Round int `json:"round"`
|
Round int `json:"round"`
|
||||||
BlockPartsHeader PartSetHeader `json:"block_parts_header"`
|
BlockPartsHeader PartSetHeader `json:"block_parts_header"`
|
||||||
POLRound int `json:"pol_round"` // -1 if null.
|
POLRound int `json:"pol_round"` // -1 if null.
|
||||||
|
POLBlockID BlockID `json:"pol_block_id"` // zero if null.
|
||||||
Signature crypto.SignatureEd25519 `json:"signature"`
|
Signature crypto.SignatureEd25519 `json:"signature"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// polRound: -1 if no polRound.
|
// polRound: -1 if no polRound.
|
||||||
func NewProposal(height int, round int, blockPartsHeader PartSetHeader, polRound int) *Proposal {
|
func NewProposal(height int, round int, blockPartsHeader PartSetHeader, polRound int, polBlockID BlockID) *Proposal {
|
||||||
return &Proposal{
|
return &Proposal{
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
BlockPartsHeader: blockPartsHeader,
|
BlockPartsHeader: blockPartsHeader,
|
||||||
POLRound: polRound,
|
POLRound: polRound,
|
||||||
|
POLBlockID: polBlockID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proposal) String() string {
|
func (p *Proposal) String() string {
|
||||||
return fmt.Sprintf("Proposal{%v/%v %v %v %v}", p.Height, p.Round,
|
return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %v}", p.Height, p.Round,
|
||||||
p.BlockPartsHeader, p.POLRound, p.Signature)
|
p.BlockPartsHeader, p.POLRound, p.POLBlockID, p.Signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
|
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(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err)
|
||||||
wire.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err)
|
wire.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err)
|
||||||
p.BlockPartsHeader.WriteSignBytes(w, n, err)
|
p.BlockPartsHeader.WriteSignBytes(w, n, err)
|
||||||
wire.WriteTo([]byte(Fmt(`,"height":%v,"pol_round":%v`, p.Height, p.POLRound)), 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.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err)
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,8 @@ func TestProposalSignable(t *testing.T) {
|
|||||||
signBytes := SignBytes("test_chain_id", proposal)
|
signBytes := SignBytes("test_chain_id", proposal)
|
||||||
signStr := string(signBytes)
|
signStr := string(signBytes)
|
||||||
|
|
||||||
expected := `{"chain_id":"test_chain_id","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_round":-1,"round":23456}}`
|
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}}`
|
||||||
if signStr != expected {
|
if signStr != expected {
|
||||||
t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr)
|
t.Errorf("Got unexpected sign string for Proposal. Expected:\n%v\nGot:\n%v", expected, signStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
types/vote_test.go
Normal file
30
types/vote_test.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVoteSignable(t *testing.T) {
|
||||||
|
vote := &Vote{
|
||||||
|
ValidatorAddress: []byte("addr"),
|
||||||
|
ValidatorIndex: 56789,
|
||||||
|
Height: 12345,
|
||||||
|
Round: 23456,
|
||||||
|
Type: byte(2),
|
||||||
|
BlockID: BlockID{
|
||||||
|
Hash: []byte("hash"),
|
||||||
|
PartsHeader: PartSetHeader{
|
||||||
|
Total: 1000000,
|
||||||
|
Hash: []byte("parts_hash"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
signBytes := SignBytes("test_chain_id", vote)
|
||||||
|
signStr := string(signBytes)
|
||||||
|
|
||||||
|
expected := `{"chain_id":"test_chain_id","vote":{"block_id":{"hash":"68617368","parts":{"hash":"70617274735F68617368","total":1000000}},"height":12345,"round":23456,"type":2}}`
|
||||||
|
if signStr != expected {
|
||||||
|
// NOTE: when this fails, you probably want to fix up consensus/replay_test too
|
||||||
|
t.Errorf("Got unexpected sign string for Vote. Expected:\n%v\nGot:\n%v", expected, signStr)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user