From f55135578c5b6a5aa06012c17cb41ff20b00975f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Dec 2017 14:27:37 -0500 Subject: [PATCH] state: move methods to funcs --- consensus/replay.go | 2 +- evidence/pool.go | 12 +- rpc/core/blocks.go | 3 +- rpc/core/consensus.go | 3 +- state/db.go | 199 +++++++++++++++++++++++++++++++++ state/execution.go | 77 +++++++++---- state/state.go | 248 ++---------------------------------------- state/state_test.go | 41 ++++--- types/services.go | 9 -- 9 files changed, 299 insertions(+), 295 deletions(-) create mode 100644 state/db.go diff --git a/consensus/replay.go b/consensus/replay.go index 209ea5972..a9aaeefcf 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -301,7 +301,7 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int64, proxyApp } else if appBlockHeight == storeBlockHeight { // We ran Commit, but didn't save the state, so replayBlock with mock app - abciResponses, err := h.state.LoadABCIResponses(storeBlockHeight) + abciResponses, err := sm.LoadABCIResponses(h.state.DB(), storeBlockHeight) if err != nil { return nil, err } diff --git a/evidence/pool.go b/evidence/pool.go index 2296ac028..1965d0632 100644 --- a/evidence/pool.go +++ b/evidence/pool.go @@ -9,22 +9,24 @@ import ( // EvidencePool maintains a pool of valid evidence // in an EvidenceStore. type EvidencePool struct { - params types.EvidenceParams logger log.Logger - state types.State // TODO: update this on commit! evidenceStore *EvidenceStore + chainID string + lastBlockHeight int64 + params types.EvidenceParams + // never close evidenceChan chan types.Evidence } -func NewEvidencePool(params types.EvidenceParams, evidenceStore *EvidenceStore, state types.State) *EvidencePool { +func NewEvidencePool(params types.EvidenceParams, evidenceStore *EvidenceStore, state *types.State) *EvidencePool { evpool := &EvidencePool{ params: params, logger: log.NewNopLogger(), evidenceStore: evidenceStore, - state: state, + state: *state, evidenceChan: make(chan types.Evidence), } return evpool @@ -56,7 +58,7 @@ func (evpool *EvidencePool) AddEvidence(evidence types.Evidence) (err error) { // TODO: check if we already have evidence for this // validator at this height so we dont get spammed - priority, err := evpool.state.VerifyEvidence(evidence) + priority, err := sm.VerifyEvidence(evpool.state, evidence) if err != nil { // TODO: if err is just that we cant find it cuz we pruned, ignore. // TODO: if its actually bad evidence, punish peer diff --git a/rpc/core/blocks.go b/rpc/core/blocks.go index 43edcd356..8b0ee4592 100644 --- a/rpc/core/blocks.go +++ b/rpc/core/blocks.go @@ -4,6 +4,7 @@ import ( "fmt" ctypes "github.com/tendermint/tendermint/rpc/core/types" + sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" ) @@ -337,7 +338,7 @@ func BlockResults(heightPtr *int64) (*ctypes.ResultBlockResults, error) { // load the results state := consensusState.GetState() - results, err := state.LoadABCIResponses(height) + results, err := sm.LoadABCIResponses(state.DB(), height) if err != nil { return nil, err } diff --git a/rpc/core/consensus.go b/rpc/core/consensus.go index e358c4874..eedcce277 100644 --- a/rpc/core/consensus.go +++ b/rpc/core/consensus.go @@ -4,6 +4,7 @@ import ( cm "github.com/tendermint/tendermint/consensus" cstypes "github.com/tendermint/tendermint/consensus/types" ctypes "github.com/tendermint/tendermint/rpc/core/types" + sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" ) @@ -50,7 +51,7 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) { } state := consensusState.GetState() - validators, err := state.LoadValidators(height) + validators, err := sm.LoadValidators(state.DB(), height) if err != nil { return nil, err } diff --git a/state/db.go b/state/db.go new file mode 100644 index 000000000..5174b9cb3 --- /dev/null +++ b/state/db.go @@ -0,0 +1,199 @@ +package state + +import ( + "bytes" + "fmt" + + abci "github.com/tendermint/abci/types" + wire "github.com/tendermint/go-wire" + "github.com/tendermint/tendermint/types" + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" +) + +//------------------------------------------------------------------------ + +// ABCIResponses retains the responses +// of the various ABCI calls during block processing. +// It is persisted to disk for each height before calling Commit. +type ABCIResponses struct { + DeliverTx []*abci.ResponseDeliverTx + EndBlock *abci.ResponseEndBlock +} + +// NewABCIResponses returns a new ABCIResponses +func NewABCIResponses(block *types.Block) *ABCIResponses { + return &ABCIResponses{ + DeliverTx: make([]*abci.ResponseDeliverTx, block.NumTxs), + } +} + +// Bytes serializes the ABCIResponse using go-wire +func (a *ABCIResponses) Bytes() []byte { + return wire.BinaryBytes(*a) +} + +func (a *ABCIResponses) ResultsHash() []byte { + results := types.NewResults(a.DeliverTx) + return results.Hash() +} + +// 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(). It can also be used to produce Merkle proofs of the result of txs. +func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) { + buf := db.Get(calcABCIResponsesKey(height)) + if len(buf) == 0 { + return nil, ErrNoABCIResponsesForHeight{height} + } + + abciResponses := new(ABCIResponses) + r, n, err := bytes.NewReader(buf), new(int), new(error) + wire.ReadBinaryPtr(abciResponses, r, 0, n, err) + if *err != nil { + // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED + cmn.Exit(cmn.Fmt(`LoadABCIResponses: Data has been corrupted or its spec has + changed: %v\n`, *err)) + } + // TODO: ensure that buf is completely read. + + return abciResponses, nil +} + +// SaveABCIResponses persists the ABCIResponses to the database. +// This is useful in case we crash after app.Commit and before s.Save(). +// Responses are indexed by height so they can also be loaded later to produce Merkle proofs. +func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) { + db.SetSync(calcABCIResponsesKey(height), abciResponses.Bytes()) +} + +//----------------------------------------------------------------------------- + +// ValidatorsInfo represents the latest validator set, or the last height it changed +type ValidatorsInfo struct { + ValidatorSet *types.ValidatorSet + LastHeightChanged int64 +} + +// Bytes serializes the ValidatorsInfo using go-wire +func (valInfo *ValidatorsInfo) Bytes() []byte { + return wire.BinaryBytes(*valInfo) +} + +// LoadValidators loads the ValidatorSet for a given height. +// Returns ErrNoValSetForHeight if the validator set can't be found for this height. +func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) { + valInfo := loadValidatorsInfo(db, height) + if valInfo == nil { + return nil, ErrNoValSetForHeight{height} + } + + if valInfo.ValidatorSet == nil { + valInfo = loadValidatorsInfo(db, valInfo.LastHeightChanged) + if valInfo == nil { + cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as + last changed from height %d`, valInfo.LastHeightChanged, height)) + } + } + + return valInfo.ValidatorSet, nil +} + +func loadValidatorsInfo(db dbm.DB, height int64) *ValidatorsInfo { + buf := db.Get(calcValidatorsKey(height)) + if len(buf) == 0 { + return nil + } + + v := new(ValidatorsInfo) + r, n, err := bytes.NewReader(buf), new(int), new(error) + wire.ReadBinaryPtr(v, r, 0, n, err) + if *err != nil { + // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED + cmn.Exit(cmn.Fmt(`LoadValidators: Data has been corrupted or its spec has changed: + %v\n`, *err)) + } + // TODO: ensure that buf is completely read. + + return v +} + +// saveValidatorsInfo persists the validator set for the next block to disk. +// It should be called from s.Save(), right before the state itself is persisted. +// If the validator set did not change after processing the latest block, +// only the last height for which the validators changed is persisted. +func saveValidatorsInfo(db dbm.DB, nextHeight, changeHeight int64, valSet *types.ValidatorSet) { + valInfo := &ValidatorsInfo{ + LastHeightChanged: changeHeight, + } + if changeHeight == nextHeight { + valInfo.ValidatorSet = valSet + } + db.SetSync(calcValidatorsKey(nextHeight), valInfo.Bytes()) +} + +//----------------------------------------------------------------------------- + +// ConsensusParamsInfo represents the latest consensus params, or the last height it changed +type ConsensusParamsInfo struct { + ConsensusParams types.ConsensusParams + LastHeightChanged int64 +} + +// Bytes serializes the ConsensusParamsInfo using go-wire +func (params ConsensusParamsInfo) Bytes() []byte { + return wire.BinaryBytes(params) +} + +// LoadConsensusParams loads the ConsensusParams for a given height. +func LoadConsensusParams(db dbm.DB, height int64) (types.ConsensusParams, error) { + empty := types.ConsensusParams{} + + paramsInfo := loadConsensusParamsInfo(db, height) + if paramsInfo == nil { + return empty, ErrNoConsensusParamsForHeight{height} + } + + if paramsInfo.ConsensusParams == empty { + paramsInfo = loadConsensusParamsInfo(db, paramsInfo.LastHeightChanged) + if paramsInfo == nil { + cmn.PanicSanity(fmt.Sprintf(`Couldn't find consensus params at height %d as + last changed from height %d`, paramsInfo.LastHeightChanged, height)) + } + } + + return paramsInfo.ConsensusParams, nil +} + +func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo { + buf := db.Get(calcConsensusParamsKey(height)) + if len(buf) == 0 { + return nil + } + + paramsInfo := new(ConsensusParamsInfo) + r, n, err := bytes.NewReader(buf), new(int), new(error) + wire.ReadBinaryPtr(paramsInfo, r, 0, n, err) + if *err != nil { + // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED + cmn.Exit(cmn.Fmt(`LoadConsensusParams: Data has been corrupted or its spec has changed: + %v\n`, *err)) + } + // TODO: ensure that buf is completely read. + + return paramsInfo +} + +// saveConsensusParamsInfo persists the consensus params for the next block to disk. +// It should be called from s.Save(), right before the state itself is persisted. +// If the consensus params did not change after processing the latest block, +// only the last height for which they changed is persisted. +func saveConsensusParamsInfo(db dbm.DB, nextHeight, changeHeight int64, params types.ConsensusParams) { + paramsInfo := &ConsensusParamsInfo{ + LastHeightChanged: changeHeight, + } + if changeHeight == nextHeight { + paramsInfo.ConsensusParams = params + } + db.SetSync(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes()) +} diff --git a/state/execution.go b/state/execution.go index c96861524..b56f61f95 100644 --- a/state/execution.go +++ b/state/execution.go @@ -209,28 +209,9 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *types.ValidatorSet, up return false, nil } -// return a bit array of validators that signed the last commit -// NOTE: assumes commits have already been authenticated -/* function is currently unused -func commitBitArrayFromBlock(block *types.Block) *cmn.BitArray { - signed := cmn.NewBitArray(len(block.LastCommit.Precommits)) - for i, precommit := range block.LastCommit.Precommits { - if precommit != nil { - signed.SetIndex(i, true) // val_.LastCommitHeight = block.Height - 1 - } - } - return signed -} -*/ - //----------------------------------------------------- // Validate block -// ValidateBlock validates the block against the state. -func (s *State) ValidateBlock(block *types.Block) error { - return s.validateBlock(block) -} - // MakeBlock builds a block with the given txs and commit from the current state. func (s *State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (*types.Block, *types.PartSet) { // build base block @@ -248,7 +229,12 @@ func (s *State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (* return block, block.MakePartSet(s.ConsensusParams.BlockGossip.BlockPartSizeBytes) } -func (s *State) validateBlock(b *types.Block) error { +// ValidateBlock validates the block against the state. +func (s State) ValidateBlock(block *types.Block) error { + return s.validateBlock(block) +} + +func (s State) validateBlock(b *types.Block) error { // validate internal consistency if err := b.ValidateBasic(); err != nil { return err @@ -310,7 +296,7 @@ func (s *State) validateBlock(b *types.Block) error { } for _, ev := range b.Evidence.Evidence { - if _, err := s.VerifyEvidence(ev); err != nil { + if _, err := VerifyEvidence(s, ev); err != nil { return types.NewEvidenceInvalidErr(ev, err) } } @@ -318,10 +304,57 @@ func (s *State) validateBlock(b *types.Block) error { return nil } +// VerifyEvidence verifies the evidence fully by checking it is internally +// consistent and corresponds to an existing or previous validator. +// It returns the priority of this evidence, or an error. +// NOTE: return error may be ErrNoValSetForHeight, in which case the validator set +// for the evidence height could not be loaded. +func VerifyEvidence(s State, evidence types.Evidence) (priority int64, err error) { + height := s.LastBlockHeight + evidenceAge := height - evidence.Height() + maxAge := s.ConsensusParams.EvidenceParams.MaxAge + if evidenceAge > maxAge { + return priority, fmt.Errorf("Evidence from height %d is too old. Min height is %d", + evidence.Height(), height-maxAge) + } + + if err := evidence.Verify(s.ChainID); err != nil { + return priority, err + } + + // The address must have been an active validator at the height + ev := evidence + height, addr, idx := ev.Height(), ev.Address(), ev.Index() + valset, err := LoadValidators(s.db, height) + if err != nil { + // XXX/TODO: what do we do if we can't load the valset? + // eg. if we have pruned the state or height is too high? + return priority, err + } + valIdx, val := valset.GetByAddress(addr) + if val == nil { + return priority, fmt.Errorf("Address %X was not a validator at height %d", addr, height) + } else if idx != valIdx { + return priority, fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx) + } + + priority = val.VotingPower + return priority, nil +} + //----------------------------------------------------------------------------- // ApplyBlock validates & executes the block, updates state w/ ABCI responses, // then commits and updates the mempool atomically, then saves state. +// BlockExecutor provides the context and accessories for properly executing a block. +type BlockExecutor struct { + txEventPublisher types.TxEventPublisher + proxyApp proxy.AppConnConsensus + + mempool types.Mempool + evpool types.EvidencePool +} + // ApplyBlock validates the block against the state, executes it against the app, // commits it, and saves the block and state. It's the only function that needs to be called // from outside this package to process and commit an entire block. @@ -337,7 +370,7 @@ func (s *State) ApplyBlock(txEventPublisher types.TxEventPublisher, proxyAppConn fail.Fail() // XXX // save the results before we commit - s.SaveABCIResponses(block.Height, abciResponses) + SaveABCIResponses(s.db, block.Height, abciResponses) fail.Fail() // XXX diff --git a/state/state.go b/state/state.go index 773b46fcc..1aaddeb3a 100644 --- a/state/state.go +++ b/state/state.go @@ -4,11 +4,8 @@ import ( "bytes" "fmt" "io/ioutil" - "sync" "time" - abci "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -44,9 +41,7 @@ func calcABCIResponsesKey(height int64) []byte { // but the fields should only be changed by calling state.SetBlockAndValidators. // NOTE: not goroutine-safe. type State struct { - // mtx for writing to db - mtx sync.Mutex - db dbm.DB + db dbm.DB // Immutable ChainID string @@ -82,6 +77,10 @@ type State struct { logger log.Logger } +func (s *State) DB() dbm.DB { + return s.db +} + // GetState loads the most recent state from the database, // or creates a new one from the given genesisFile and persists the result // to the database. @@ -157,150 +156,13 @@ func (s *State) Copy() *State { // Save persists the State to the database. func (s *State) Save() { - s.mtx.Lock() - defer s.mtx.Unlock() - - s.saveValidatorsInfo() - s.saveConsensusParamsInfo() - 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(). -// 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 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(). 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, ErrNoABCIResponsesForHeight{height} - } - - abciResponses := new(ABCIResponses) - r, n, err := bytes.NewReader(buf), new(int), new(error) - wire.ReadBinaryPtr(abciResponses, r, 0, n, err) - if *err != nil { - // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED - cmn.Exit(cmn.Fmt(`LoadABCIResponses: Data has been corrupted or its spec has - changed: %v\n`, *err)) - } - // TODO: ensure that buf is completely read. - - return abciResponses, nil -} - -// LoadValidators loads the ValidatorSet for a given height. -// Returns ErrNoValSetForHeight if the validator set can't be found for this height. -func (s *State) LoadValidators(height int64) (*types.ValidatorSet, error) { - valInfo := s.loadValidatorsInfo(height) - if valInfo == nil { - return nil, ErrNoValSetForHeight{height} - } - - if valInfo.ValidatorSet == nil { - valInfo = s.loadValidatorsInfo(valInfo.LastHeightChanged) - if valInfo == nil { - cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as - last changed from height %d`, valInfo.LastHeightChanged, height)) - } - } - - return valInfo.ValidatorSet, nil -} - -func (s *State) loadValidatorsInfo(height int64) *ValidatorsInfo { - buf := s.db.Get(calcValidatorsKey(height)) - if len(buf) == 0 { - return nil - } - - v := new(ValidatorsInfo) - r, n, err := bytes.NewReader(buf), new(int), new(error) - wire.ReadBinaryPtr(v, r, 0, n, err) - if *err != nil { - // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED - cmn.Exit(cmn.Fmt(`LoadValidators: Data has been corrupted or its spec has changed: - %v\n`, *err)) - } - // TODO: ensure that buf is completely read. - - return v -} - -// saveValidatorsInfo persists the validator set for the next block to disk. -// It should be called from s.Save(), right before the state itself is persisted. -// If the validator set did not change after processing the latest block, -// only the last height for which the validators changed is persisted. -func (s *State) saveValidatorsInfo() { - changeHeight := s.LastHeightValidatorsChanged nextHeight := s.LastBlockHeight + 1 - valInfo := &ValidatorsInfo{ - LastHeightChanged: changeHeight, - } - if changeHeight == nextHeight { - valInfo.ValidatorSet = s.Validators - } - s.db.SetSync(calcValidatorsKey(nextHeight), valInfo.Bytes()) -} - -// LoadConsensusParams loads the ConsensusParams for a given height. -func (s *State) LoadConsensusParams(height int64) (types.ConsensusParams, error) { - empty := types.ConsensusParams{} - - paramsInfo := s.loadConsensusParamsInfo(height) - if paramsInfo == nil { - return empty, ErrNoConsensusParamsForHeight{height} - } - - if paramsInfo.ConsensusParams == empty { - paramsInfo = s.loadConsensusParamsInfo(paramsInfo.LastHeightChanged) - if paramsInfo == nil { - cmn.PanicSanity(fmt.Sprintf(`Couldn't find consensus params at height %d as - last changed from height %d`, paramsInfo.LastHeightChanged, height)) - } - } - return paramsInfo.ConsensusParams, nil -} - -func (s *State) loadConsensusParamsInfo(height int64) *ConsensusParamsInfo { - buf := s.db.Get(calcConsensusParamsKey(height)) - if len(buf) == 0 { - return nil - } - - paramsInfo := new(ConsensusParamsInfo) - r, n, err := bytes.NewReader(buf), new(int), new(error) - wire.ReadBinaryPtr(paramsInfo, r, 0, n, err) - if *err != nil { - // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED - cmn.Exit(cmn.Fmt(`LoadConsensusParams: Data has been corrupted or its spec has changed: - %v\n`, *err)) - } - // TODO: ensure that buf is completely read. - - return paramsInfo -} - -// saveConsensusParamsInfo persists the consensus params for the next block to disk. -// It should be called from s.Save(), right before the state itself is persisted. -// If the consensus params did not change after processing the latest block, -// only the last height for which they changed is persisted. -func (s *State) saveConsensusParamsInfo() { - changeHeight := s.LastHeightConsensusParamsChanged - nextHeight := s.LastBlockHeight + 1 - paramsInfo := &ConsensusParamsInfo{ - LastHeightChanged: changeHeight, - } - if changeHeight == nextHeight { - paramsInfo.ConsensusParams = s.ConsensusParams - } - s.db.SetSync(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes()) + // persist everything to db + db := s.db + saveValidatorsInfo(db, nextHeight, s.LastHeightValidatorsChanged, s.Validators) + saveConsensusParamsInfo(db, nextHeight, s.LastHeightConsensusParamsChanged, s.ConsensusParams) + db.SetSync(stateKey, s.Bytes()) } // Equals returns true if the States are identical. @@ -383,96 +245,6 @@ func (s *State) GetValidators() (last *types.ValidatorSet, current *types.Valida return s.LastValidators, s.Validators } -// VerifyEvidence verifies the evidence fully by checking it is internally -// consistent and corresponds to an existing or previous validator. -// It returns the priority of this evidence, or an error. -// NOTE: return error may be ErrNoValSetForHeight, in which case the validator set -// for the evidence height could not be loaded. -func (s *State) VerifyEvidence(evidence types.Evidence) (priority int64, err error) { - evidenceAge := s.LastBlockHeight - evidence.Height() - maxAge := s.ConsensusParams.EvidenceParams.MaxAge - if evidenceAge > maxAge { - return priority, fmt.Errorf("Evidence from height %d is too old. Min height is %d", - evidence.Height(), s.LastBlockHeight-maxAge) - } - - if err := evidence.Verify(s.ChainID); err != nil { - return priority, err - } - - // The address must have been an active validator at the height - ev := evidence - height, addr, idx := ev.Height(), ev.Address(), ev.Index() - valset, err := s.LoadValidators(height) - if err != nil { - // XXX/TODO: what do we do if we can't load the valset? - // eg. if we have pruned the state or height is too high? - return priority, err - } - valIdx, val := valset.GetByAddress(addr) - if val == nil { - return priority, fmt.Errorf("Address %X was not a validator at height %d", addr, height) - } else if idx != valIdx { - return priority, fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx) - } - - priority = val.VotingPower - return priority, nil -} - -//------------------------------------------------------------------------ - -// ABCIResponses retains the responses -// of the various ABCI calls during block processing. -// It is persisted to disk for each height before calling Commit. -type ABCIResponses struct { - DeliverTx []*abci.ResponseDeliverTx - EndBlock *abci.ResponseEndBlock -} - -// NewABCIResponses returns a new ABCIResponses -func NewABCIResponses(block *types.Block) *ABCIResponses { - return &ABCIResponses{ - DeliverTx: make([]*abci.ResponseDeliverTx, block.NumTxs), - } -} - -// Bytes serializes the ABCIResponse using go-wire -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 -type ValidatorsInfo struct { - ValidatorSet *types.ValidatorSet - LastHeightChanged int64 -} - -// Bytes serializes the ValidatorsInfo using go-wire -func (valInfo *ValidatorsInfo) Bytes() []byte { - return wire.BinaryBytes(*valInfo) -} - -//----------------------------------------------------------------------------- - -// ConsensusParamsInfo represents the latest consensus params, or the last height it changed -type ConsensusParamsInfo struct { - ConsensusParams types.ConsensusParams - LastHeightChanged int64 -} - -// Bytes serializes the ConsensusParamsInfo using go-wire -func (params ConsensusParamsInfo) Bytes() []byte { - return wire.BinaryBytes(params) -} - //------------------------------------------------------------------------ // Genesis diff --git a/state/state_test.go b/state/state_test.go index b1adc0d02..486ad24aa 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -88,8 +88,8 @@ func TestABCIResponsesSaveLoad1(t *testing.T) { }, }} - state.SaveABCIResponses(block.Height, abciResponses) - loadedAbciResponses, err := state.LoadABCIResponses(block.Height) + SaveABCIResponses(state.db, block.Height, abciResponses) + loadedAbciResponses, err := LoadABCIResponses(state.db, block.Height) assert.Nil(err) assert.Equal(abciResponses, loadedAbciResponses, cmn.Fmt(`ABCIResponses don't match: Got %v, Expected %v`, loadedAbciResponses, @@ -142,7 +142,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { // query all before, should return error for i := range cases { h := int64(i + 1) - res, err := state.LoadABCIResponses(h) + res, err := LoadABCIResponses(state.db, h) assert.Error(err, "%d: %#v", i, res) } @@ -153,13 +153,13 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { DeliverTx: tc.added, EndBlock: &abci.ResponseEndBlock{}, } - state.SaveABCIResponses(h, responses) + SaveABCIResponses(state.db, h, responses) } // query all before, should return expected value for i, tc := range cases { h := int64(i + 1) - res, err := state.LoadABCIResponses(h) + res, err := LoadABCIResponses(state.db, h) assert.NoError(err, "%d", i) assert.Equal(tc.expected.Hash(), res.ResultsHash(), "%d", i) } @@ -173,30 +173,32 @@ func TestValidatorSimpleSaveLoad(t *testing.T) { assert := assert.New(t) // can't load anything for height 0 - v, err := state.LoadValidators(0) + v, err := LoadValidators(state.db, 0) assert.IsType(ErrNoValSetForHeight{}, err, "expected err at height 0") // should be able to load for height 1 - v, err = state.LoadValidators(1) + v, err = LoadValidators(state.db, 1) assert.Nil(err, "expected no err at height 1") assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match") // increment height, save; should be able to load for next height state.LastBlockHeight++ - state.saveValidatorsInfo() - v, err = state.LoadValidators(state.LastBlockHeight + 1) + nextHeight := state.LastBlockHeight + 1 + saveValidatorsInfo(state.db, nextHeight, state.LastHeightValidatorsChanged, state.Validators) + v, err = LoadValidators(state.db, nextHeight) assert.Nil(err, "expected no err") assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match") // increment height, save; should be able to load for next height state.LastBlockHeight += 10 - state.saveValidatorsInfo() - v, err = state.LoadValidators(state.LastBlockHeight + 1) + nextHeight = state.LastBlockHeight + 1 + saveValidatorsInfo(state.db, nextHeight, state.LastHeightValidatorsChanged, state.Validators) + v, err = LoadValidators(state.db, nextHeight) assert.Nil(err, "expected no err") assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match") // should be able to load for next next height - _, err = state.LoadValidators(state.LastBlockHeight + 2) + _, err = LoadValidators(state.db, state.LastBlockHeight+2) assert.IsType(ErrNoValSetForHeight{}, err, "expected err at unknown height") } @@ -225,7 +227,8 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { header, parts, responses := makeHeaderPartsResponsesValPowerChange(state, i, power) err := state.SetBlockAndValidators(header, parts, responses) assert.Nil(t, err) - state.saveValidatorsInfo() + nextHeight := state.LastBlockHeight + 1 + saveValidatorsInfo(state.db, nextHeight, state.LastHeightValidatorsChanged, state.Validators) } // on each change height, increment the power by one. @@ -243,7 +246,7 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { } for i, power := range testCases { - v, err := state.LoadValidators(int64(i + 1)) + v, err := LoadValidators(state.db, int64(i+1)) assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", i)) assert.Equal(t, v.Size(), 1, "validator set size is greater than 1: %d", v.Size()) _, val := v.GetByIndex(0) @@ -268,9 +271,10 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) { header, parts, responses := makeHeaderPartsResponsesValPubKeyChange(state, height, pubkey) err := state.SetBlockAndValidators(header, parts, responses) require.Nil(t, err) - state.saveValidatorsInfo() + nextHeight := state.LastBlockHeight + 1 + saveValidatorsInfo(state.db, nextHeight, state.LastHeightValidatorsChanged, state.Validators) - v, err := state.LoadValidators(height + 1) + v, err := LoadValidators(state.db, height+1) assert.Nil(t, err) assert.Equal(t, valSetSize, v.Size()) @@ -323,7 +327,8 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { header, parts, responses := makeHeaderPartsResponsesParams(state, i, cp) err := state.SetBlockAndValidators(header, parts, responses) require.Nil(t, err) - state.saveConsensusParamsInfo() + nextHeight := state.LastBlockHeight + 1 + saveConsensusParamsInfo(state.db, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams) } // make all the test cases by using the same params until after the change @@ -341,7 +346,7 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { } for _, testCase := range testCases { - p, err := state.LoadConsensusParams(testCase.height) + p, err := LoadConsensusParams(state.db, testCase.height) assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", testCase.height)) assert.Equal(t, testCase.params, p, fmt.Sprintf(`unexpected consensus params at height %d`, testCase.height)) diff --git a/types/services.go b/types/services.go index 787b1b99e..a901898f9 100644 --- a/types/services.go +++ b/types/services.go @@ -70,15 +70,6 @@ type BlockStore interface { SaveBlock(block *Block, blockParts *PartSet, seenCommit *Commit) } -//------------------------------------------------------ -// state - -// State defines the stateful interface used to verify evidence. -// UNSTABLE -type State interface { - VerifyEvidence(Evidence) (priority int64, err error) -} - //------------------------------------------------------ // evidence pool