reconstruct last commit works with legacy chains

This commit is contained in:
William Banfield
2022-05-13 14:05:01 -04:00
parent ec46cc4006
commit c3f64df354
2 changed files with 66 additions and 17 deletions
+45 -17
View File
@@ -695,27 +695,55 @@ func (cs *State) sendInternalMessage(ctx context.Context, mi msgInfo) {
// Reconstruct LastCommit from SeenCommit, which we saved along with the block,
// (which happens even before saving the state)
func (cs *State) reconstructLastCommit(state sm.State) {
extCommit := cs.blockStore.LoadExtendedCommit(state.LastBlockHeight)
if extCommit == nil {
panic(fmt.Sprintf(
"failed to reconstruct last commit; commit for height %v not found",
state.LastBlockHeight,
))
}
requireExtensions := false
requireHeight := cs.state.ConsensusParams.Vote.ExtensionRequireHeight
if requireHeight != 0 && extCommit.Height >= requireHeight {
if err := extCommit.EnsureExtensions(); err != nil {
panic(fmt.Sprintf("failed to reconstruct last commit; invalid vote extensions: %v", err))
}
if requireHeight != 0 && state.LastBlockHeight >= requireHeight {
requireExtensions = true
}
votes, err := cs.votesFromExtendedCommit(state)
if err == nil {
cs.LastCommit = votes
return
}
if requireExtensions {
panic(fmt.Sprintf("failed to reconstruct last commit; %s", err))
}
votes, err = cs.votesFromSeenCommit(state)
if err != nil {
panic(fmt.Sprintf("failed to reconstruct last commit; %s", err))
}
cs.LastCommit = votes
}
func (cs *State) votesFromExtendedCommit(state sm.State) (*types.VoteSet, error) {
ec := cs.blockStore.LoadExtendedCommit(state.LastBlockHeight)
if ec == nil {
return nil, fmt.Errorf("commit for height %v not found", state.LastBlockHeight)
}
if err := ec.EnsureExtensions(); err != nil {
return nil, fmt.Errorf("invalid vote extensions: %v", err)
}
vs := ec.ToVoteSet(state.ChainID, state.LastValidators)
if !vs.HasTwoThirdsMajority() {
return nil, errors.New("seen commit does not have +2/3 majority")
}
return vs, nil
}
func (cs *State) votesFromSeenCommit(state sm.State) (*types.VoteSet, error) {
commit := cs.blockStore.LoadSeenCommit()
if commit == nil || commit.Height != state.LastBlockHeight {
commit = cs.blockStore.LoadBlockCommit(state.LastBlockHeight)
}
if commit == nil {
return nil, fmt.Errorf("commit for height %v not found", state.LastBlockHeight)
}
lastPrecommits := extCommit.ToVoteSet(state.ChainID, state.LastValidators)
if !lastPrecommits.HasTwoThirdsMajority() {
panic("failed to reconstruct last commit; does not have +2/3 maj")
vs := commit.ToVoteSet(state.ChainID, state.LastValidators)
if !vs.HasTwoThirdsMajority() {
return nil, errors.New("commit does not have +2/3 majority")
}
cs.LastCommit = lastPrecommits
return vs, nil
}
// Updates State and increments height to match that of state.
+21
View File
@@ -1038,6 +1038,27 @@ func (ec *ExtendedCommit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet
return voteSet
}
// ToVoteSet constructs a VoteSet from the Commit and validator set.
// Panics if signatures from the commit can't be added to the voteset.
// Inverse of VoteSet.MakeCommit().
func (c *Commit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet {
voteSet := NewVoteSet(chainID, c.Height, c.Round, tmproto.PrecommitType, vals)
for idx, cs := range c.Signatures {
if cs.BlockIDFlag == BlockIDFlagAbsent {
continue // OK, some precommits can be missing.
}
vote := c.GetVote(int32(idx))
if err := vote.ValidateBasic(); err != nil {
panic(fmt.Errorf("failed to validate vote reconstructed from commit: %w", err))
}
added, err := voteSet.AddVote(vote)
if !added || err != nil {
panic(fmt.Errorf("failed to reconstruct vote set from commit: %w", err))
}
}
return voteSet
}
// TODO Comment
// this should probably also verify the signature
// probably want to change to just verify when present.