mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-15 14:21:22 +00:00
state: move methods to funcs
This commit is contained in:
@ -301,7 +301,7 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int64, proxyApp
|
|||||||
|
|
||||||
} else if appBlockHeight == storeBlockHeight {
|
} else if appBlockHeight == storeBlockHeight {
|
||||||
// We ran Commit, but didn't save the state, so replayBlock with mock app
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,24 @@ import (
|
|||||||
// EvidencePool maintains a pool of valid evidence
|
// EvidencePool maintains a pool of valid evidence
|
||||||
// in an EvidenceStore.
|
// in an EvidenceStore.
|
||||||
type EvidencePool struct {
|
type EvidencePool struct {
|
||||||
params types.EvidenceParams
|
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
|
|
||||||
state types.State // TODO: update this on commit!
|
|
||||||
evidenceStore *EvidenceStore
|
evidenceStore *EvidenceStore
|
||||||
|
|
||||||
|
chainID string
|
||||||
|
lastBlockHeight int64
|
||||||
|
params types.EvidenceParams
|
||||||
|
|
||||||
// never close
|
// never close
|
||||||
evidenceChan chan types.Evidence
|
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{
|
evpool := &EvidencePool{
|
||||||
params: params,
|
params: params,
|
||||||
logger: log.NewNopLogger(),
|
logger: log.NewNopLogger(),
|
||||||
evidenceStore: evidenceStore,
|
evidenceStore: evidenceStore,
|
||||||
state: state,
|
state: *state,
|
||||||
evidenceChan: make(chan types.Evidence),
|
evidenceChan: make(chan types.Evidence),
|
||||||
}
|
}
|
||||||
return evpool
|
return evpool
|
||||||
@ -56,7 +58,7 @@ func (evpool *EvidencePool) AddEvidence(evidence types.Evidence) (err error) {
|
|||||||
// TODO: check if we already have evidence for this
|
// TODO: check if we already have evidence for this
|
||||||
// validator at this height so we dont get spammed
|
// 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 {
|
if err != nil {
|
||||||
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
||||||
// TODO: if its actually bad evidence, punish peer
|
// TODO: if its actually bad evidence, punish peer
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
@ -337,7 +338,7 @@ func BlockResults(heightPtr *int64) (*ctypes.ResultBlockResults, error) {
|
|||||||
|
|
||||||
// load the results
|
// load the results
|
||||||
state := consensusState.GetState()
|
state := consensusState.GetState()
|
||||||
results, err := state.LoadABCIResponses(height)
|
results, err := sm.LoadABCIResponses(state.DB(), height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
cm "github.com/tendermint/tendermint/consensus"
|
cm "github.com/tendermint/tendermint/consensus"
|
||||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state := consensusState.GetState()
|
state := consensusState.GetState()
|
||||||
validators, err := state.LoadValidators(height)
|
validators, err := sm.LoadValidators(state.DB(), height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
199
state/db.go
Normal file
199
state/db.go
Normal file
@ -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())
|
||||||
|
}
|
@ -209,28 +209,9 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *types.ValidatorSet, up
|
|||||||
return false, nil
|
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
|
// 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.
|
// 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) {
|
func (s *State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (*types.Block, *types.PartSet) {
|
||||||
// build base block
|
// 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)
|
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
|
// validate internal consistency
|
||||||
if err := b.ValidateBasic(); err != nil {
|
if err := b.ValidateBasic(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -310,7 +296,7 @@ func (s *State) validateBlock(b *types.Block) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ev := range b.Evidence.Evidence {
|
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)
|
return types.NewEvidenceInvalidErr(ev, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,10 +304,57 @@ func (s *State) validateBlock(b *types.Block) error {
|
|||||||
return nil
|
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,
|
// ApplyBlock validates & executes the block, updates state w/ ABCI responses,
|
||||||
// then commits and updates the mempool atomically, then saves state.
|
// 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,
|
// 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
|
// 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.
|
// 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
|
fail.Fail() // XXX
|
||||||
|
|
||||||
// save the results before we commit
|
// save the results before we commit
|
||||||
s.SaveABCIResponses(block.Height, abciResponses)
|
SaveABCIResponses(s.db, block.Height, abciResponses)
|
||||||
|
|
||||||
fail.Fail() // XXX
|
fail.Fail() // XXX
|
||||||
|
|
||||||
|
246
state/state.go
246
state/state.go
@ -4,11 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
@ -44,8 +41,6 @@ func calcABCIResponsesKey(height int64) []byte {
|
|||||||
// but the fields should only be changed by calling state.SetBlockAndValidators.
|
// but the fields should only be changed by calling state.SetBlockAndValidators.
|
||||||
// NOTE: not goroutine-safe.
|
// NOTE: not goroutine-safe.
|
||||||
type State struct {
|
type State struct {
|
||||||
// mtx for writing to db
|
|
||||||
mtx sync.Mutex
|
|
||||||
db dbm.DB
|
db dbm.DB
|
||||||
|
|
||||||
// Immutable
|
// Immutable
|
||||||
@ -82,6 +77,10 @@ type State struct {
|
|||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) DB() dbm.DB {
|
||||||
|
return s.db
|
||||||
|
}
|
||||||
|
|
||||||
// GetState loads the most recent state from the database,
|
// GetState loads the most recent state from the database,
|
||||||
// or creates a new one from the given genesisFile and persists the result
|
// or creates a new one from the given genesisFile and persists the result
|
||||||
// to the database.
|
// to the database.
|
||||||
@ -157,150 +156,13 @@ func (s *State) Copy() *State {
|
|||||||
|
|
||||||
// Save persists the State to the database.
|
// Save persists the State to the database.
|
||||||
func (s *State) Save() {
|
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
|
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.
|
// persist everything to db
|
||||||
func (s *State) LoadConsensusParams(height int64) (types.ConsensusParams, error) {
|
db := s.db
|
||||||
empty := types.ConsensusParams{}
|
saveValidatorsInfo(db, nextHeight, s.LastHeightValidatorsChanged, s.Validators)
|
||||||
|
saveConsensusParamsInfo(db, nextHeight, s.LastHeightConsensusParamsChanged, s.ConsensusParams)
|
||||||
paramsInfo := s.loadConsensusParamsInfo(height)
|
db.SetSync(stateKey, s.Bytes())
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals returns true if the States are identical.
|
// 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
|
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
|
// Genesis
|
||||||
|
|
||||||
|
@ -88,8 +88,8 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
state.SaveABCIResponses(block.Height, abciResponses)
|
SaveABCIResponses(state.db, block.Height, abciResponses)
|
||||||
loadedAbciResponses, err := state.LoadABCIResponses(block.Height)
|
loadedAbciResponses, err := LoadABCIResponses(state.db, block.Height)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(abciResponses, loadedAbciResponses,
|
assert.Equal(abciResponses, loadedAbciResponses,
|
||||||
cmn.Fmt(`ABCIResponses don't match: Got %v, Expected %v`, 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
|
// query all before, should return error
|
||||||
for i := range cases {
|
for i := range cases {
|
||||||
h := int64(i + 1)
|
h := int64(i + 1)
|
||||||
res, err := state.LoadABCIResponses(h)
|
res, err := LoadABCIResponses(state.db, h)
|
||||||
assert.Error(err, "%d: %#v", i, res)
|
assert.Error(err, "%d: %#v", i, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,13 +153,13 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
|
|||||||
DeliverTx: tc.added,
|
DeliverTx: tc.added,
|
||||||
EndBlock: &abci.ResponseEndBlock{},
|
EndBlock: &abci.ResponseEndBlock{},
|
||||||
}
|
}
|
||||||
state.SaveABCIResponses(h, responses)
|
SaveABCIResponses(state.db, h, responses)
|
||||||
}
|
}
|
||||||
|
|
||||||
// query all before, should return expected value
|
// query all before, should return expected value
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
h := int64(i + 1)
|
h := int64(i + 1)
|
||||||
res, err := state.LoadABCIResponses(h)
|
res, err := LoadABCIResponses(state.db, h)
|
||||||
assert.NoError(err, "%d", i)
|
assert.NoError(err, "%d", i)
|
||||||
assert.Equal(tc.expected.Hash(), res.ResultsHash(), "%d", i)
|
assert.Equal(tc.expected.Hash(), res.ResultsHash(), "%d", i)
|
||||||
}
|
}
|
||||||
@ -173,30 +173,32 @@ func TestValidatorSimpleSaveLoad(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
// can't load anything for height 0
|
// 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")
|
assert.IsType(ErrNoValSetForHeight{}, err, "expected err at height 0")
|
||||||
|
|
||||||
// should be able to load for height 1
|
// 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.Nil(err, "expected no err at height 1")
|
||||||
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
||||||
|
|
||||||
// increment height, save; should be able to load for next height
|
// increment height, save; should be able to load for next height
|
||||||
state.LastBlockHeight++
|
state.LastBlockHeight++
|
||||||
state.saveValidatorsInfo()
|
nextHeight := state.LastBlockHeight + 1
|
||||||
v, err = state.LoadValidators(state.LastBlockHeight + 1)
|
saveValidatorsInfo(state.db, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
||||||
|
v, err = LoadValidators(state.db, nextHeight)
|
||||||
assert.Nil(err, "expected no err")
|
assert.Nil(err, "expected no err")
|
||||||
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
||||||
|
|
||||||
// increment height, save; should be able to load for next height
|
// increment height, save; should be able to load for next height
|
||||||
state.LastBlockHeight += 10
|
state.LastBlockHeight += 10
|
||||||
state.saveValidatorsInfo()
|
nextHeight = state.LastBlockHeight + 1
|
||||||
v, err = state.LoadValidators(state.LastBlockHeight + 1)
|
saveValidatorsInfo(state.db, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
||||||
|
v, err = LoadValidators(state.db, nextHeight)
|
||||||
assert.Nil(err, "expected no err")
|
assert.Nil(err, "expected no err")
|
||||||
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
||||||
|
|
||||||
// should be able to load for next next height
|
// 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")
|
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)
|
header, parts, responses := makeHeaderPartsResponsesValPowerChange(state, i, power)
|
||||||
err := state.SetBlockAndValidators(header, parts, responses)
|
err := state.SetBlockAndValidators(header, parts, responses)
|
||||||
assert.Nil(t, err)
|
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.
|
// on each change height, increment the power by one.
|
||||||
@ -243,7 +246,7 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, power := range testCases {
|
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.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())
|
assert.Equal(t, v.Size(), 1, "validator set size is greater than 1: %d", v.Size())
|
||||||
_, val := v.GetByIndex(0)
|
_, val := v.GetByIndex(0)
|
||||||
@ -268,9 +271,10 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) {
|
|||||||
header, parts, responses := makeHeaderPartsResponsesValPubKeyChange(state, height, pubkey)
|
header, parts, responses := makeHeaderPartsResponsesValPubKeyChange(state, height, pubkey)
|
||||||
err := state.SetBlockAndValidators(header, parts, responses)
|
err := state.SetBlockAndValidators(header, parts, responses)
|
||||||
require.Nil(t, err)
|
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.Nil(t, err)
|
||||||
assert.Equal(t, valSetSize, v.Size())
|
assert.Equal(t, valSetSize, v.Size())
|
||||||
|
|
||||||
@ -323,7 +327,8 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
|||||||
header, parts, responses := makeHeaderPartsResponsesParams(state, i, cp)
|
header, parts, responses := makeHeaderPartsResponsesParams(state, i, cp)
|
||||||
err := state.SetBlockAndValidators(header, parts, responses)
|
err := state.SetBlockAndValidators(header, parts, responses)
|
||||||
require.Nil(t, err)
|
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
|
// 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 {
|
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.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
|
assert.Equal(t, testCase.params, p, fmt.Sprintf(`unexpected consensus params at
|
||||||
height %d`, testCase.height))
|
height %d`, testCase.height))
|
||||||
|
@ -70,15 +70,6 @@ type BlockStore interface {
|
|||||||
SaveBlock(block *Block, blockParts *PartSet, seenCommit *Commit)
|
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
|
// evidence pool
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user