/
consensus_prevote.go
140 lines (119 loc) · 4.53 KB
/
consensus_prevote.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package consensus
import (
"bytes"
"fmt"
"time"
cstypes "github.com/brc20-collab/brczero/libs/tendermint/consensus/types"
"github.com/brc20-collab/brczero/libs/tendermint/libs/automation"
"github.com/brc20-collab/brczero/libs/tendermint/types"
)
// Enter: `timeoutPropose` after entering Propose.
// Enter: proposal block and POL is ready.
// Prevote for LockedBlock if we're locked, or ProposalBlock if valid.
// Otherwise vote nil.
func (cs *State) enterPrevote(height int64, round int) {
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevote <= cs.Step) {
cs.Logger.Debug(fmt.Sprintf(
"enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
cs.initNewHeight()
cs.trc.Pin("Prevote-%d", round)
defer func() {
// Done enterPrevote:
cs.updateRoundStep(round, cstypes.RoundStepPrevote)
cs.newStep()
}()
cs.Logger.Info(fmt.Sprintf("enterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
// Sign and broadcast vote as necessary
cs.doPrevote(height, round)
// Once `addVote` hits any +2/3 prevotes, we will go to PrevoteWait
// (so we have more time to try and collect +2/3 prevotes for a single block)
}
func (cs *State) defaultDoPrevote(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
if automation.PrevoteNil(height, round) {
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
return
}
// If a block is locked, prevote that.
if cs.LockedBlock != nil {
logger.Info("enterPrevote: Block was locked")
cs.signAddVote(types.PrevoteType, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header())
return
}
// If ProposalBlock is nil, prevote nil.
if cs.ProposalBlock == nil {
logger.Info("enterPrevote: ProposalBlock is nil")
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
return
}
// Validate proposal block
err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock)
if err != nil {
// ProposalBlock is invalid, prevote nil.
logger.Error("enterPrevote: ProposalBlock is invalid", "err", err)
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
return
}
// when block is received, verify the block data and ord data
brczeroData := types.ZeroData{}
for times := 1; times <= BrczeroRetryTimes; times++ {
brczeroData, err = cs.blockExec.GetZeroDataByBTCHeight(cs.ProposalBlock.BtcHeight)
if err == nil {
break
}
time.Sleep(time.Second)
}
if err != nil {
cs.Logger.Error("Zero data not exist!", "BTCHeight", cs.ProposalBlock.BtcHeight)
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
return
}
if !bytes.Equal(brczeroData.ZeroHash(), cs.ProposalBlock.Txs.ZeroHash()) || brczeroData.BTCBlockHash != cs.ProposalBlock.BtcBlockHash {
if cs.ProposalBlock.BtcBlockHash == "" {
cs.Logger.Error("ProposalBlock.BtcBlockHash is empty!", "BTCHeight")
} else {
cs.Logger.Error("Zero data not equal!", "BTCHeight", cs.ProposalBlock.BtcHeight, "localORDBlockHash: ", brczeroData.BTCBlockHash, "BTCBlockHash", cs.ProposalBlock.BtcBlockHash)
}
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
return
}
// Prevote cs.ProposalBlock
// NOTE: the proposal signature is validated when it is received,
// and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
logger.Info("enterPrevote: ProposalBlock is valid")
cs.signAddVote(types.PrevoteType, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
}
// Enter: any +2/3 prevotes at next round.
func (cs *State) enterPrevoteWait(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) {
logger.Debug(fmt.Sprintf(
"enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
cs.initNewHeight()
cs.trc.Pin("PrevoteWait-%d", round)
if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
panic(fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round))
}
logger.Info(fmt.Sprintf("enterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
defer func() {
// Done enterPrevoteWait:
cs.updateRoundStep(round, cstypes.RoundStepPrevoteWait)
cs.newStep()
}()
// Wait for some more prevotes; enterPrecommit
cs.scheduleTimeout(cs.config.Prevote(round), height, round, cstypes.RoundStepPrevoteWait)
}