Skip to content

Commit

Permalink
merge main and manually add back missing method
Browse files Browse the repository at this point in the history
  • Loading branch information
danwt committed Apr 17, 2024
2 parents 410e35c + 25afe20 commit 6425efb
Show file tree
Hide file tree
Showing 23 changed files with 651 additions and 350 deletions.
81 changes: 51 additions & 30 deletions block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,31 @@ import (
// applyBlock applies the block to the store and the abci app.
// steps: save block -> execute block with app -> update state -> commit block to app -> update store height and state hash.
// As the entire process can't be atomic we need to make sure the following condition apply before
// we're applying the block in the happy path: block height - 1 == abci app last block height.
// In case the following doesn't hold true, it means we crashed after the commit and before updating the store height.
// In that case we'll want to align the store with the app state and continue to the next block.
// - block height is the expected block height on the store (height + 1).
// - block height is the expected block height on the app (last block height + 1).
func (m *Manager) applyBlock(ctx context.Context, block *types.Block, commit *types.Commit, blockMetaData blockMetaData) error {
if block.Header.Height != m.store.Height()+1 {
// We crashed after the commit and before updating the store height.
m.logger.Error("Block not applied. Wrong height", "block height", block.Header.Height, "store height", m.store.Height())
return nil
// TODO (#330): allow genesis block with height > 0 to be applied.
// TODO: add switch case to have defined behavior for each case.
// validate block height
if block.Header.Height != m.store.NextHeight() {
m.logger.Error("Block not applied. wrong height", "block height", block.Header.Height, "expected height", m.store.NextHeight())
return types.ErrInvalidBlockHeight
}

m.logger.Debug("Applying block", "height", block.Header.Height, "source", blockMetaData.source)

// Check if alignment is needed due to incosistencies between the store and the app.
isAlignRequired, err := m.alignStoreWithApp(ctx, block)
// Check if the app's last block height is the same as the currently produced block height
isBlockAlreadyApplied, err := m.isHeightAlreadyApplied(block.Header.Height)
if err != nil {
return err
}
if isAlignRequired {
// In case the following true, it means we crashed after the commit and before updating the store height.
// In that case we'll want to align the store with the app state and continue to the next block.
if isBlockAlreadyApplied {
err := m.UpdateStateFromApp()
if err != nil {
return err
}
m.logger.Debug("Aligned with app state required. Skipping to next block", "height", block.Header.Height)
return nil
}
Expand Down Expand Up @@ -117,17 +124,22 @@ func (m *Manager) attemptApplyCachedBlocks(ctx context.Context) error {
m.applyCachedBlockMutex.Lock()
defer m.applyCachedBlockMutex.Unlock()

prevCachedBlock, exists := m.prevBlock[m.store.Height()+1]
for {
expectedHeight := m.store.NextHeight()

for exists {
m.logger.Debug("Applying cached block", "height", m.store.Height()+1)
prevCachedBlock, blockExists := m.prevBlock[expectedHeight]
prevCachedCommit, commitExists := m.prevCommit[expectedHeight]

err := m.applyBlock(ctx, prevCachedBlock, m.prevCommit[m.store.Height()+1], blockMetaData{source: gossipedBlock})
if !blockExists || !commitExists {
break
}

m.logger.Debug("Applying cached block", "height", expectedHeight)
err := m.applyBlock(ctx, prevCachedBlock, prevCachedCommit, blockMetaData{source: gossipedBlock})
if err != nil {
m.logger.Debug("apply previously cached block", "err", err)
return err
}
prevCachedBlock, exists = m.prevBlock[m.store.Height()+1]
}

for k := range m.prevBlock {
Expand All @@ -139,37 +151,46 @@ func (m *Manager) attemptApplyCachedBlocks(ctx context.Context) error {
return nil
}

// alignStoreWithApp is responsible for aligning the state of the store and the abci app if necessary.
func (m *Manager) alignStoreWithApp(ctx context.Context, block *types.Block) (bool, error) {
isRequired := false
// Validate incosistency in height wasn't caused by a crash and if so handle it.
// isHeightAlreadyApplied checks if the block height is already applied to the app.
func (m *Manager) isHeightAlreadyApplied(blockHeight uint64) (bool, error) {
proxyAppInfo, err := m.executor.GetAppInfo()
if err != nil {
return isRequired, errors.Wrap(err, "get app info")
return false, errors.Wrap(err, "get app info")
}
if uint64(proxyAppInfo.LastBlockHeight) != block.Header.Height {
return isRequired, nil

isBlockAlreadyApplied := uint64(proxyAppInfo.LastBlockHeight) == blockHeight

// TODO: add switch case to validate better the current app state

return isBlockAlreadyApplied, nil
}

// UpdateStateFromApp is responsible for aligning the state of the store from the abci app
func (m *Manager) UpdateStateFromApp() error {
proxyAppInfo, err := m.executor.GetAppInfo()
if err != nil {
return errors.Wrap(err, "get app info")
}

isRequired = true
m.logger.Info("Skipping block application and only updating store height and state hash", "height", block.Header.Height)
appHeight := uint64(proxyAppInfo.LastBlockHeight)

// update the state with the hash, last store height and last validators.
m.lastState.AppHash = *(*[32]byte)(proxyAppInfo.LastBlockAppHash)
m.lastState.LastStoreHeight = block.Header.Height
m.lastState.LastStoreHeight = appHeight
m.lastState.LastValidators = m.lastState.Validators.Copy()

resp, err := m.store.LoadBlockResponses(block.Header.Height)
resp, err := m.store.LoadBlockResponses(appHeight)
if err != nil {
return isRequired, errors.Wrap(err, "load block responses")
return errors.Wrap(err, "load block responses")
}
copy(m.lastState.LastResultsHash[:], tmtypes.NewResults(resp.DeliverTxs).Hash())

_, err = m.store.UpdateState(m.lastState, nil)
if err != nil {
return isRequired, errors.Wrap(err, "update state")
return errors.Wrap(err, "update state")
}
m.store.SetHeight(block.Header.Height)
return isRequired, nil
m.store.SetHeight(appHeight)
return nil
}

func (m *Manager) executeBlock(ctx context.Context, block *types.Block, commit *types.Commit) (*tmstate.ABCIResponses, error) {
Expand Down
Loading

0 comments on commit 6425efb

Please sign in to comment.