mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-18 07:31:20 +00:00
state: ApplyBlock
This commit is contained in:
@ -181,7 +181,58 @@ func (txErr InvalidTxError) Error() string {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Replay all blocks after blockHeight and ensure the result matches the current state
|
||||
// mempool must be locked during commit and update
|
||||
// because state is typically reset on Commit and old txs must be replayed
|
||||
// against committed state before new txs are run in the mempool, lest they be invalid
|
||||
func (s *State) CommitStateUpdateMempool(proxyAppConn proxy.AppConnConsensus, block *types.Block, mempool Mempool) error {
|
||||
mempool.Lock()
|
||||
defer mempool.Unlock()
|
||||
|
||||
// flush out any CheckTx that have already started
|
||||
// cs.proxyAppConn.FlushSync() // ?! XXX
|
||||
|
||||
// Commit block, get hash back
|
||||
res := proxyAppConn.CommitSync()
|
||||
if res.IsErr() {
|
||||
log.Warn("Error in proxyAppConn.CommitSync", "error", res)
|
||||
return res
|
||||
}
|
||||
if res.Log != "" {
|
||||
log.Debug("Commit.Log: " + res.Log)
|
||||
}
|
||||
|
||||
// Set the state's new AppHash
|
||||
s.AppHash = res.Data
|
||||
|
||||
// Update mempool.
|
||||
mempool.Update(block.Height, block.Txs)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execute and commit block against app, save block and state
|
||||
func (s *State) ApplyBlock(eventCache events.Fireable, proxyAppConn proxy.AppConnConsensus,
|
||||
block *types.Block, partsHeader types.PartSetHeader, mempool Mempool) {
|
||||
|
||||
// Run the block on the State:
|
||||
// + update validator sets
|
||||
// + run txs on the proxyAppConn
|
||||
err := s.ExecBlock(eventCache, proxyAppConn, block, partsHeader)
|
||||
if err != nil {
|
||||
// TODO: handle this gracefully.
|
||||
PanicQ(Fmt("Exec failed for application: %v", err))
|
||||
}
|
||||
|
||||
// lock mempool, commit state, update mempoool
|
||||
err = s.CommitStateUpdateMempool(proxyAppConn, block, mempool)
|
||||
if err != nil {
|
||||
// TODO: handle this gracefully.
|
||||
PanicQ(Fmt("Commit failed for application: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Replay all blocks after blockHeight and ensure the result matches the current state.
|
||||
// XXX: blockStore must guarantee to have blocks for height <= blockStore.Height()
|
||||
func (s *State) ReplayBlocks(header *types.Header, partsHeader types.PartSetHeader,
|
||||
appConnConsensus proxy.AppConnConsensus, blockStore proxy.BlockStore) error {
|
||||
|
||||
@ -197,36 +248,16 @@ func (s *State) ReplayBlocks(header *types.Header, partsHeader types.PartSetHead
|
||||
stateCopy.SetBlockAndValidators(header, partsHeader, lastVals, nextVals)
|
||||
}
|
||||
|
||||
// run the transactions
|
||||
var eventCache events.Fireable // nil
|
||||
|
||||
// replay all blocks starting with blockHeight+1
|
||||
for i := blockHeight + 1; i <= blockStore.Height(); i++ {
|
||||
blockMeta := blockStore.LoadBlockMeta(i)
|
||||
if blockMeta == nil {
|
||||
PanicSanity(Fmt("Nil blockMeta at height %d when blockStore height is %d", i, blockStore.Height()))
|
||||
}
|
||||
|
||||
block := blockStore.LoadBlock(i)
|
||||
if block == nil {
|
||||
PanicSanity(Fmt("Nil block at height %d when blockStore height is %d", i, blockStore.Height()))
|
||||
}
|
||||
panicOnNilBlock(i, blockStore.Height(), block, blockMeta) // XXX
|
||||
|
||||
// run the transactions
|
||||
var eventCache events.Fireable // nil
|
||||
err := stateCopy.ExecBlock(eventCache, appConnConsensus, block, blockMeta.PartsHeader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error on ExecBlock: %v", err)
|
||||
}
|
||||
|
||||
// commit the block (app should save the state)
|
||||
res := appConnConsensus.CommitSync()
|
||||
if res.IsErr() {
|
||||
return fmt.Errorf("Error on Commit: %v", res)
|
||||
}
|
||||
if res.Log != "" {
|
||||
log.Debug("Commit.Log: " + res.Log)
|
||||
}
|
||||
|
||||
// update the state hash
|
||||
stateCopy.AppHash = res.Data
|
||||
stateCopy.ApplyBlock(eventCache, appConnConsensus, block, blockMeta.PartsHeader, mockMempool{})
|
||||
}
|
||||
|
||||
// The computed state and the previously set state should be identical
|
||||
@ -235,3 +266,32 @@ func (s *State) ReplayBlocks(header *types.Header, partsHeader types.PartSetHead
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func panicOnNilBlock(height, bsHeight int, block *types.Block, blockMeta *types.BlockMeta) {
|
||||
if block == nil || blockMeta == nil {
|
||||
// Sanity?
|
||||
PanicCrisis(Fmt(`
|
||||
block/blockMeta is nil for height <= blockStore.Height() (%d <= %d).
|
||||
Block: %v,
|
||||
BlockMeta: %v
|
||||
`, height, bsHeight, block, blockMeta))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Updates to the mempool need to be synchronized with committing a block
|
||||
// so apps can reset their transient state on Commit
|
||||
|
||||
type Mempool interface {
|
||||
Lock()
|
||||
Unlock()
|
||||
Update(height int, txs []types.Tx)
|
||||
}
|
||||
|
||||
type mockMempool struct {
|
||||
}
|
||||
|
||||
func (m mockMempool) Lock() {}
|
||||
func (m mockMempool) Unlock() {}
|
||||
func (m mockMempool) Update(height int, txs []types.Tx) {}
|
||||
|
Reference in New Issue
Block a user