mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-05 21:14:53 +00:00
genesis: add support for arbitrary initial height (#5191)
Adds a genesis parameter `initial_height` which specifies the initial block height, as well as ABCI `RequestInitChain.InitialHeight` to pass it to the ABCI application, and `State.InitialHeight` to keep track of the initial height throughout the code. Fixes #2543, based on [RFC-002](https://github.com/tendermint/spec/pull/119). Spec changes in https://github.com/tendermint/spec/pull/135.
This commit is contained in:
@@ -555,27 +555,33 @@ func (cs *State) updateToState(state sm.State) {
|
||||
panic(fmt.Sprintf("updateToState() expected state height of %v but found %v",
|
||||
cs.Height, state.LastBlockHeight))
|
||||
}
|
||||
if !cs.state.IsEmpty() && cs.state.LastBlockHeight+1 != cs.Height {
|
||||
// This might happen when someone else is mutating cs.state.
|
||||
// Someone forgot to pass in state.Copy() somewhere?!
|
||||
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v",
|
||||
cs.state.LastBlockHeight+1, cs.Height))
|
||||
}
|
||||
if !cs.state.IsEmpty() {
|
||||
if cs.state.LastBlockHeight > 0 && cs.state.LastBlockHeight+1 != cs.Height {
|
||||
// This might happen when someone else is mutating cs.state.
|
||||
// Someone forgot to pass in state.Copy() somewhere?!
|
||||
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v",
|
||||
cs.state.LastBlockHeight+1, cs.Height))
|
||||
}
|
||||
if cs.state.LastBlockHeight > 0 && cs.Height == cs.state.InitialHeight {
|
||||
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight %v, expected 0 for initial height %v",
|
||||
cs.state.LastBlockHeight, cs.state.InitialHeight))
|
||||
}
|
||||
|
||||
// If state isn't further out than cs.state, just ignore.
|
||||
// This happens when SwitchToConsensus() is called in the reactor.
|
||||
// We don't want to reset e.g. the Votes, but we still want to
|
||||
// signal the new round step, because other services (eg. txNotifier)
|
||||
// depend on having an up-to-date peer state!
|
||||
if !cs.state.IsEmpty() && (state.LastBlockHeight <= cs.state.LastBlockHeight) {
|
||||
cs.Logger.Info(
|
||||
"Ignoring updateToState()",
|
||||
"newHeight",
|
||||
state.LastBlockHeight+1,
|
||||
"oldHeight",
|
||||
cs.state.LastBlockHeight+1)
|
||||
cs.newStep()
|
||||
return
|
||||
// If state isn't further out than cs.state, just ignore.
|
||||
// This happens when SwitchToConsensus() is called in the reactor.
|
||||
// We don't want to reset e.g. the Votes, but we still want to
|
||||
// signal the new round step, because other services (eg. txNotifier)
|
||||
// depend on having an up-to-date peer state!
|
||||
if state.LastBlockHeight <= cs.state.LastBlockHeight {
|
||||
cs.Logger.Info(
|
||||
"Ignoring updateToState()",
|
||||
"newHeight",
|
||||
state.LastBlockHeight+1,
|
||||
"oldHeight",
|
||||
cs.state.LastBlockHeight+1)
|
||||
cs.newStep()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Reset fields based on state.
|
||||
@@ -595,13 +601,16 @@ func (cs *State) updateToState(state sm.State) {
|
||||
case cs.LastCommit == nil:
|
||||
// NOTE: when Tendermint starts, it has no votes. reconstructLastCommit
|
||||
// must be called to reconstruct LastCommit from SeenCommit.
|
||||
panic(fmt.Sprintf("LastCommit cannot be empty in heights > 1 (H:%d)",
|
||||
panic(fmt.Sprintf("LastCommit cannot be empty after initial block (H:%d)",
|
||||
state.LastBlockHeight+1,
|
||||
))
|
||||
}
|
||||
|
||||
// Next desired block height
|
||||
height := state.LastBlockHeight + 1
|
||||
if height == 1 {
|
||||
height = state.InitialHeight
|
||||
}
|
||||
|
||||
// RoundState fields
|
||||
cs.updateHeight(height)
|
||||
@@ -933,7 +942,7 @@ func (cs *State) enterNewRound(height int64, round int32) {
|
||||
// needProofBlock returns true on the first height (so the genesis app hash is signed right away)
|
||||
// and where the last block (height-1) caused the app hash to change
|
||||
func (cs *State) needProofBlock(height int64) bool {
|
||||
if height == 1 {
|
||||
if height == cs.state.InitialHeight {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1090,7 +1099,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa
|
||||
|
||||
var commit *types.Commit
|
||||
switch {
|
||||
case cs.Height == 1:
|
||||
case cs.Height == cs.state.InitialHeight:
|
||||
// We're creating a proposal for the first block.
|
||||
// The commit is empty, but not nil.
|
||||
commit = types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
@@ -1607,7 +1616,7 @@ func (cs *State) recordMetrics(height int64, block *types.Block) {
|
||||
// height=0 -> MissingValidators and MissingValidatorsPower are both 0.
|
||||
// Remember that the first LastCommit is intentionally empty, so it's not
|
||||
// fair to increment missing validators number.
|
||||
if height > 1 {
|
||||
if height > cs.state.InitialHeight {
|
||||
// Sanity check that commit size matches validator set size - only applies
|
||||
// after first block.
|
||||
var (
|
||||
@@ -1818,7 +1827,7 @@ func (cs *State) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) {
|
||||
return added, err
|
||||
}
|
||||
var timestamp time.Time
|
||||
if voteErr.VoteA.Height == 1 {
|
||||
if voteErr.VoteA.Height == cs.state.InitialHeight {
|
||||
timestamp = cs.state.LastBlockTime // genesis time
|
||||
} else {
|
||||
timestamp = sm.MedianTime(cs.LastCommit.MakeCommit(), cs.LastValidators)
|
||||
|
||||
Reference in New Issue
Block a user