|
|
@ -20,8 +20,7 @@ import ( |
|
|
|
|
|
|
|
// database keys
|
|
|
|
var ( |
|
|
|
stateKey = []byte("stateKey") |
|
|
|
abciResponsesKey = []byte("abciResponsesKey") |
|
|
|
stateKey = []byte("stateKey") |
|
|
|
) |
|
|
|
|
|
|
|
func calcValidatorsKey(height int64) []byte { |
|
|
@ -32,8 +31,8 @@ func calcConsensusParamsKey(height int64) []byte { |
|
|
|
return []byte(cmn.Fmt("consensusParamsKey:%v", height)) |
|
|
|
} |
|
|
|
|
|
|
|
func calcResultsKey(height int64) []byte { |
|
|
|
return []byte(cmn.Fmt("resultsKey:%v", height)) |
|
|
|
func calcABCIResponsesKey(height int64) []byte { |
|
|
|
return []byte(cmn.Fmt("abciResponsesKey:%v", height)) |
|
|
|
} |
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@ -75,10 +74,8 @@ type State struct { |
|
|
|
LastConsensusParams types.ConsensusParams |
|
|
|
LastHeightConsensusParamsChanged int64 |
|
|
|
|
|
|
|
// Store LastABCIResults along with hash
|
|
|
|
LastResults types.ABCIResults // TODO: remove??
|
|
|
|
LastResultHash []byte // this is the one for the next block to propose
|
|
|
|
LastLastResultHash []byte // this verifies the last block?
|
|
|
|
// Merkle root of the results from executing prev block
|
|
|
|
LastResultHash []byte |
|
|
|
|
|
|
|
// The latest AppHash we've received from calling abci.Commit()
|
|
|
|
AppHash []byte |
|
|
@ -154,7 +151,6 @@ func (s *State) Copy() *State { |
|
|
|
|
|
|
|
AppHash: s.AppHash, |
|
|
|
|
|
|
|
LastResults: s.LastResults, |
|
|
|
LastResultHash: s.LastResultHash, |
|
|
|
|
|
|
|
logger: s.logger, |
|
|
@ -168,23 +164,23 @@ func (s *State) Save() { |
|
|
|
|
|
|
|
s.saveValidatorsInfo() |
|
|
|
s.saveConsensusParamsInfo() |
|
|
|
s.saveResults() |
|
|
|
s.db.SetSync(stateKey, s.Bytes()) |
|
|
|
} |
|
|
|
|
|
|
|
// SaveABCIResponses persists the ABCIResponses to the database.
|
|
|
|
// This is useful in case we crash after app.Commit and before s.Save().
|
|
|
|
func (s *State) SaveABCIResponses(abciResponses *ABCIResponses) { |
|
|
|
s.db.SetSync(abciResponsesKey, abciResponses.Bytes()) |
|
|
|
// Responses are indexed by height so they can also be loaded later to produce Merkle proofs.
|
|
|
|
func (s *State) SaveABCIResponses(height int64, abciResponses *ABCIResponses) { |
|
|
|
s.db.SetSync(calcABCIResponsesKey(height), abciResponses.Bytes()) |
|
|
|
} |
|
|
|
|
|
|
|
// LoadABCIResponses loads the ABCIResponses from the database.
|
|
|
|
// LoadABCIResponses loads the ABCIResponses for the given height from the database.
|
|
|
|
// This is useful for recovering from crashes where we called app.Commit and before we called
|
|
|
|
// s.Save()
|
|
|
|
func (s *State) LoadABCIResponses() *ABCIResponses { |
|
|
|
buf := s.db.Get(abciResponsesKey) |
|
|
|
// s.Save(). It can also be used to produce Merkle proofs of the result of txs.
|
|
|
|
func (s *State) LoadABCIResponses(height int64) (*ABCIResponses, error) { |
|
|
|
buf := s.db.Get(calcABCIResponsesKey(height)) |
|
|
|
if len(buf) == 0 { |
|
|
|
return nil |
|
|
|
return nil, ErrNoABCIResponsesForHeight{height} |
|
|
|
} |
|
|
|
|
|
|
|
abciResponses := new(ABCIResponses) |
|
|
@ -197,7 +193,7 @@ func (s *State) LoadABCIResponses() *ABCIResponses { |
|
|
|
} |
|
|
|
// TODO: ensure that buf is completely read.
|
|
|
|
|
|
|
|
return abciResponses |
|
|
|
return abciResponses, nil |
|
|
|
} |
|
|
|
|
|
|
|
// LoadValidators loads the ValidatorSet for a given height.
|
|
|
@ -308,39 +304,6 @@ func (s *State) saveConsensusParamsInfo() { |
|
|
|
s.db.SetSync(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes()) |
|
|
|
} |
|
|
|
|
|
|
|
// LoadResults loads the types.ABCIResults for a given height.
|
|
|
|
func (s *State) LoadResults(height int64) (types.ABCIResults, error) { |
|
|
|
resInfo := s.loadResults(height) |
|
|
|
if resInfo == nil { |
|
|
|
return nil, ErrNoResultsForHeight{height} |
|
|
|
} |
|
|
|
return resInfo, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (s *State) loadResults(height int64) types.ABCIResults { |
|
|
|
buf := s.db.Get(calcResultsKey(height)) |
|
|
|
if len(buf) == 0 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
v := new(types.ABCIResults) |
|
|
|
err := wire.ReadBinaryBytes(buf, v) |
|
|
|
if err != nil { |
|
|
|
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
|
|
|
|
cmn.Exit(cmn.Fmt(`LoadResults: Data has been corrupted or its spec has changed: |
|
|
|
%v\n`, err)) |
|
|
|
} |
|
|
|
return *v |
|
|
|
} |
|
|
|
|
|
|
|
// saveResults persists the results for the last block to disk.
|
|
|
|
// It should be called from s.Save(), right before the state itself is persisted.
|
|
|
|
func (s *State) saveResults() { |
|
|
|
nextHeight := s.LastBlockHeight + 1 |
|
|
|
results := s.LastResults |
|
|
|
s.db.SetSync(calcResultsKey(nextHeight), results.Bytes()) |
|
|
|
} |
|
|
|
|
|
|
|
// Equals returns true if the States are identical.
|
|
|
|
func (s *State) Equals(s2 *State) bool { |
|
|
|
return bytes.Equal(s.Bytes(), s2.Bytes()) |
|
|
@ -393,7 +356,7 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ |
|
|
|
header.Time, |
|
|
|
nextValSet, |
|
|
|
nextParams, |
|
|
|
types.NewResults(abciResponses.DeliverTx)) |
|
|
|
abciResponses.ResultsHash()) |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
@ -401,7 +364,7 @@ func (s *State) setBlockAndValidators(height int64, |
|
|
|
newTxs int64, blockID types.BlockID, blockTime time.Time, |
|
|
|
valSet *types.ValidatorSet, |
|
|
|
params types.ConsensusParams, |
|
|
|
results types.ABCIResults) { |
|
|
|
resultsHash []byte) { |
|
|
|
|
|
|
|
s.LastBlockHeight = height |
|
|
|
s.LastBlockTotalTx += newTxs |
|
|
@ -414,8 +377,7 @@ func (s *State) setBlockAndValidators(height int64, |
|
|
|
s.LastConsensusParams = s.ConsensusParams |
|
|
|
s.ConsensusParams = params |
|
|
|
|
|
|
|
s.LastResults = results |
|
|
|
s.LastResultHash = results.Hash() |
|
|
|
s.LastResultHash = resultsHash |
|
|
|
} |
|
|
|
|
|
|
|
// GetValidators returns the last and current validator sets.
|
|
|
@ -425,23 +387,18 @@ func (s *State) GetValidators() (last *types.ValidatorSet, current *types.Valida |
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// ABCIResponses retains the responses of the various ABCI calls during block processing.
|
|
|
|
// ABCIResponses retains the deterministic components of the responses
|
|
|
|
// of the various ABCI calls during block processing.
|
|
|
|
// It is persisted to disk before calling Commit.
|
|
|
|
type ABCIResponses struct { |
|
|
|
Height int64 |
|
|
|
|
|
|
|
DeliverTx []*abci.ResponseDeliverTx |
|
|
|
EndBlock *abci.ResponseEndBlock |
|
|
|
|
|
|
|
txs types.Txs // reference for indexing results by hash
|
|
|
|
} |
|
|
|
|
|
|
|
// NewABCIResponses returns a new ABCIResponses
|
|
|
|
func NewABCIResponses(block *types.Block) *ABCIResponses { |
|
|
|
return &ABCIResponses{ |
|
|
|
Height: block.Height, |
|
|
|
DeliverTx: make([]*abci.ResponseDeliverTx, block.NumTxs), |
|
|
|
txs: block.Data.Txs, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -450,6 +407,11 @@ func (a *ABCIResponses) Bytes() []byte { |
|
|
|
return wire.BinaryBytes(*a) |
|
|
|
} |
|
|
|
|
|
|
|
func (a *ABCIResponses) ResultsHash() []byte { |
|
|
|
results := types.NewResults(a.DeliverTx) |
|
|
|
return results.Hash() |
|
|
|
} |
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// ValidatorsInfo represents the latest validator set, or the last height it changed
|
|
|
|