|
|
@ -141,14 +141,16 @@ func (cs *ConsensusState) catchupReplay(csHeight int64) error { |
|
|
|
var msg *TimedWALMessage |
|
|
|
dec := WALDecoder{gr} |
|
|
|
|
|
|
|
LOOP: |
|
|
|
for { |
|
|
|
msg, err = dec.Decode() |
|
|
|
if err == io.EOF { |
|
|
|
break |
|
|
|
} else if IsDataCorruptionError(err) { |
|
|
|
switch { |
|
|
|
case err == io.EOF: |
|
|
|
break LOOP |
|
|
|
case IsDataCorruptionError(err): |
|
|
|
cs.Logger.Error("data has been corrupted in last height of consensus WAL", "err", err, "height", csHeight) |
|
|
|
return err |
|
|
|
} else if err != nil { |
|
|
|
case err != nil: |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
@ -333,19 +335,20 @@ func (h *Handshaker) ReplayBlocks( |
|
|
|
} |
|
|
|
|
|
|
|
// First handle edge cases and constraints on the storeBlockHeight.
|
|
|
|
if storeBlockHeight == 0 { |
|
|
|
switch { |
|
|
|
case storeBlockHeight == 0: |
|
|
|
assertAppHashEqualsOneFromState(appHash, state) |
|
|
|
return appHash, nil |
|
|
|
|
|
|
|
} else if storeBlockHeight < appBlockHeight { |
|
|
|
case storeBlockHeight < appBlockHeight: |
|
|
|
// the app should never be ahead of the store (but this is under app's control)
|
|
|
|
return appHash, sm.ErrAppBlockHeightTooHigh{CoreHeight: storeBlockHeight, AppHeight: appBlockHeight} |
|
|
|
|
|
|
|
} else if storeBlockHeight < stateBlockHeight { |
|
|
|
case storeBlockHeight < stateBlockHeight: |
|
|
|
// the state should never be ahead of the store (this is under tendermint's control)
|
|
|
|
panic(fmt.Sprintf("StateBlockHeight (%d) > StoreBlockHeight (%d)", stateBlockHeight, storeBlockHeight)) |
|
|
|
|
|
|
|
} else if storeBlockHeight > stateBlockHeight+1 { |
|
|
|
case storeBlockHeight > stateBlockHeight+1: |
|
|
|
// store should be at most one ahead of the state (this is under tendermint's control)
|
|
|
|
panic(fmt.Sprintf("StoreBlockHeight (%d) > StateBlockHeight + 1 (%d)", storeBlockHeight, stateBlockHeight+1)) |
|
|
|
} |
|
|
@ -369,12 +372,13 @@ func (h *Handshaker) ReplayBlocks( |
|
|
|
} else if storeBlockHeight == stateBlockHeight+1 { |
|
|
|
// We saved the block in the store but haven't updated the state,
|
|
|
|
// so we'll need to replay a block using the WAL.
|
|
|
|
if appBlockHeight < stateBlockHeight { |
|
|
|
switch { |
|
|
|
case appBlockHeight < stateBlockHeight: |
|
|
|
// the app is further behind than it should be, so replay blocks
|
|
|
|
// but leave the last block to go through the WAL
|
|
|
|
return h.replayBlocks(state, proxyApp, appBlockHeight, storeBlockHeight, true) |
|
|
|
|
|
|
|
} else if appBlockHeight == stateBlockHeight { |
|
|
|
case appBlockHeight == stateBlockHeight: |
|
|
|
// We haven't run Commit (both the state and app are one block behind),
|
|
|
|
// so replayBlock with the real app.
|
|
|
|
// NOTE: We could instead use the cs.WAL on cs.Start,
|
|
|
@ -383,7 +387,7 @@ func (h *Handshaker) ReplayBlocks( |
|
|
|
state, err = h.replayBlock(state, storeBlockHeight, proxyApp.Consensus()) |
|
|
|
return state.AppHash, err |
|
|
|
|
|
|
|
} else if appBlockHeight == storeBlockHeight { |
|
|
|
case appBlockHeight == storeBlockHeight: |
|
|
|
// We ran Commit, but didn't save the state, so replayBlock with mock app.
|
|
|
|
abciResponses, err := sm.LoadABCIResponses(h.stateDB, storeBlockHeight) |
|
|
|
if err != nil { |
|
|
|