Browse Source

state: proto migration (#4972)

## Description

the second part of state proto migration

Closes: #XXX
pull/4968/head
Marko 4 years ago
committed by GitHub
parent
commit
7a8224f8a3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 335 additions and 147 deletions
  1. +0
    -4
      consensus/replay.go
  2. +3
    -2
      consensus/replay_stubs.go
  3. +5
    -3
      consensus/replay_test.go
  4. +7
    -4
      evidence/pool_test.go
  5. +2
    -1
      rpc/core/blocks_test.go
  6. +8
    -5
      state/execution.go
  7. +2
    -1
      state/export_test.go
  8. +8
    -7
      state/helpers_test.go
  9. +111
    -13
      state/state.go
  10. +59
    -15
      state/state_test.go
  11. +104
    -74
      state/store.go
  12. +21
    -12
      state/store_test.go
  13. +0
    -3
      state/validation.go
  14. +3
    -2
      statesync/stateprovider.go
  15. +2
    -1
      statesync/syncer_test.go

+ 0
- 4
consensus/replay.go View File

@ -6,13 +6,9 @@ import (
"hash/crc32"
"io"
"reflect"
//"strconv"
//"strings"
"time"
abci "github.com/tendermint/tendermint/abci/types"
//auto "github.com/tendermint/tendermint/libs/autofile"
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/libs/log"


+ 3
- 2
consensus/replay_stubs.go View File

@ -4,6 +4,7 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/clist"
mempl "github.com/tendermint/tendermint/mempool"
tmstate "github.com/tendermint/tendermint/proto/state"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
@ -64,7 +65,7 @@ func (emptyEvidencePool) Header(int64) *types.Header { return nil }
// Useful because we don't want to call Commit() twice for the same block on
// the real app.
func newMockProxyApp(appHash []byte, abciResponses *sm.ABCIResponses) proxy.AppConnConsensus {
func newMockProxyApp(appHash []byte, abciResponses *tmstate.ABCIResponses) proxy.AppConnConsensus {
clientCreator := proxy.NewLocalClientCreator(&mockProxyApp{
appHash: appHash,
abciResponses: abciResponses,
@ -82,7 +83,7 @@ type mockProxyApp struct {
appHash []byte
txCount int
abciResponses *sm.ABCIResponses
abciResponses *tmstate.ABCIResponses
}
func (mock *mockProxyApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {


+ 5
- 3
consensus/replay_test.go View File

@ -28,6 +28,7 @@ import (
tmrand "github.com/tendermint/tendermint/libs/rand"
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/privval"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
@ -176,6 +177,7 @@ LOOP:
csWal, err := cs.OpenWAL(walFile)
require.NoError(t, err)
crashingWal.next = csWal
// reset the message counter
crashingWal.msgIndex = 1
cs.wal = crashingWal
@ -577,13 +579,13 @@ func TestMockProxyApp(t *testing.T) {
txIndex := 0
assert.NotPanics(t, func() {
abciResWithEmptyDeliverTx := new(sm.ABCIResponses)
abciResWithEmptyDeliverTx := new(tmstate.ABCIResponses)
abciResWithEmptyDeliverTx.DeliverTxs = make([]*abci.ResponseDeliverTx, 0)
abciResWithEmptyDeliverTx.DeliverTxs = append(abciResWithEmptyDeliverTx.DeliverTxs, &abci.ResponseDeliverTx{})
// called when saveABCIResponses:
bytes := cdc.MustMarshalBinaryBare(abciResWithEmptyDeliverTx)
loadedAbciRes := new(sm.ABCIResponses)
loadedAbciRes := new(tmstate.ABCIResponses)
// this also happens sm.LoadABCIResponses
err := cdc.UnmarshalBinaryBare(bytes, loadedAbciRes)
@ -591,7 +593,7 @@ func TestMockProxyApp(t *testing.T) {
mock := newMockProxyApp([]byte("mock_hash"), loadedAbciRes)
abciRes := new(sm.ABCIResponses)
abciRes := new(tmstate.ABCIResponses)
abciRes.DeliverTxs = make([]*abci.ResponseDeliverTx, len(loadedAbciRes.DeliverTxs))
// Execute transactions and get hash.
proxyCb := func(req *abci.Request, res *abci.Response) {


+ 7
- 4
evidence/pool_test.go View File

@ -11,6 +11,7 @@ import (
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmproto "github.com/tendermint/tendermint/proto/types"
sm "github.com/tendermint/tendermint/state"
@ -283,19 +284,21 @@ func TestRecoverPendingEvidence(t *testing.T) {
func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
stateDB := dbm.NewMemDB()
pk := ed25519.GenPrivKey().PubKey()
// create validator set and state
validator := &types.Validator{Address: valAddr, VotingPower: 100, PubKey: pk}
valSet := &types.ValidatorSet{
Validators: []*types.Validator{
{Address: valAddr, VotingPower: 0},
},
Validators: []*types.Validator{validator},
Proposer: validator,
}
state := sm.State{
LastBlockHeight: height,
LastBlockTime: tmtime.Now(),
LastValidators: valSet,
Validators: valSet,
NextValidators: valSet.CopyIncrementProposerPriority(1),
LastValidators: valSet,
LastHeightValidatorsChanged: 1,
ConsensusParams: tmproto.ConsensusParams{
Block: tmproto.BlockParams{


+ 2
- 1
rpc/core/blocks_test.go View File

@ -10,6 +10,7 @@ import (
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
tmstate "github.com/tendermint/tendermint/proto/state"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types"
sm "github.com/tendermint/tendermint/state"
@ -69,7 +70,7 @@ func TestBlockchainInfo(t *testing.T) {
}
func TestBlockResults(t *testing.T) {
results := &sm.ABCIResponses{
results := &tmstate.ABCIResponses{
DeliverTxs: []*abci.ResponseDeliverTx{
{Code: 0, Data: []byte{0x01}, Log: "ok"},
{Code: 0, Data: []byte{0x02}, Log: "ok"},


+ 8
- 5
state/execution.go View File

@ -11,6 +11,7 @@ import (
"github.com/tendermint/tendermint/libs/fail"
"github.com/tendermint/tendermint/libs/log"
mempl "github.com/tendermint/tendermint/mempool"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
@ -252,11 +253,13 @@ func execBlockOnProxyApp(
proxyAppConn proxy.AppConnConsensus,
block *types.Block,
stateDB dbm.DB,
) (*ABCIResponses, error) {
) (*tmstate.ABCIResponses, error) {
var validTxs, invalidTxs = 0, 0
txIndex := 0
abciResponses := NewABCIResponses(block)
abciResponses := new(tmstate.ABCIResponses)
dtxs := make([]*abci.ResponseDeliverTx, len(block.Txs))
abciResponses.DeliverTxs = dtxs
// Execute transactions and get hash.
proxyCb := func(req *abci.Request, res *abci.Response) {
@ -391,7 +394,7 @@ func updateState(
state State,
blockID types.BlockID,
header *types.Header,
abciResponses *ABCIResponses,
abciResponses *tmstate.ABCIResponses,
validatorUpdates []*types.Validator,
) (State, error) {
@ -444,7 +447,7 @@ func updateState(
LastHeightValidatorsChanged: lastHeightValsChanged,
ConsensusParams: nextParams,
LastHeightConsensusParamsChanged: lastHeightParamsChanged,
LastResultsHash: abciResponses.ResultsHash(),
LastResultsHash: ABCIResponsesResultsHash(*abciResponses),
AppHash: nil,
}, nil
}
@ -456,7 +459,7 @@ func fireEvents(
logger log.Logger,
eventBus types.BlockEventPublisher,
block *types.Block,
abciResponses *ABCIResponses,
abciResponses *tmstate.ABCIResponses,
validatorUpdates []*types.Validator,
) {
eventBus.PublishEventNewBlock(types.EventDataNewBlock{


+ 2
- 1
state/export_test.go View File

@ -4,6 +4,7 @@ import (
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
"github.com/tendermint/tendermint/types"
)
@ -27,7 +28,7 @@ func UpdateState(
state State,
blockID types.BlockID,
header *types.Header,
abciResponses *ABCIResponses,
abciResponses *tmstate.ABCIResponses,
validatorUpdates []*types.Validator,
) (State, error) {
return updateState(state, blockID, header, abciResponses, validatorUpdates)


+ 8
- 7
state/helpers_test.go View File

@ -11,6 +11,7 @@ import (
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
@ -121,6 +122,7 @@ func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValida
s.LastValidators = s.Validators.Copy()
sm.SaveState(stateDB, s)
}
return s, stateDB, privVals
}
@ -166,13 +168,12 @@ func makeConsensusParams(
func makeHeaderPartsResponsesValPubKeyChange(
state sm.State,
pubkey crypto.PubKey,
) (types.Header, types.BlockID, *sm.ABCIResponses) {
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
block := makeBlock(state, state.LastBlockHeight+1)
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
// If the pubkey is new, remove the old and add the new.
_, val := state.NextValidators.GetByIndex(0)
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
@ -190,10 +191,10 @@ func makeHeaderPartsResponsesValPubKeyChange(
func makeHeaderPartsResponsesValPowerChange(
state sm.State,
power int64,
) (types.Header, types.BlockID, *sm.ABCIResponses) {
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
block := makeBlock(state, state.LastBlockHeight+1)
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
@ -213,10 +214,10 @@ func makeHeaderPartsResponsesValPowerChange(
func makeHeaderPartsResponsesParams(
state sm.State,
params tmproto.ConsensusParams,
) (types.Header, types.BlockID, *sm.ABCIResponses) {
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
block := makeBlock(state, state.LastBlockHeight+1)
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(&params)},
}
return block.Header, types.BlockID{Hash: block.Hash(), PartsHeader: types.PartSetHeader{}}, abciResponses


+ 111
- 13
state/state.go View File

@ -2,10 +2,14 @@ package state
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"time"
"github.com/gogo/protobuf/proto"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
tmversion "github.com/tendermint/tendermint/proto/version"
"github.com/tendermint/tendermint/types"
@ -20,20 +24,11 @@ var (
//-----------------------------------------------------------------------------
// Version is for versioning the State.
// It holds the Block and App version needed for making blocks,
// and the software version to support upgrades to the format of
// the State as stored on disk.
type Version struct {
Consensus tmversion.Consensus
Software string
}
// InitStateVersion sets the Consensus.Block and Software versions,
// but leaves the Consensus.App version blank.
// The Consensus.App version will be set during the Handshake, once
// we hear from the app what protocol version it is running.
var InitStateVersion = Version{
var InitStateVersion = tmstate.Version{
Consensus: tmversion.Consensus{
Block: version.BlockProtocol,
App: 0,
@ -51,7 +46,7 @@ var InitStateVersion = Version{
// Instead, use state.Copy() or state.NextState(...).
// NOTE: not goroutine-safe.
type State struct {
Version Version
Version tmstate.Version
// immutable
ChainID string
@ -86,6 +81,7 @@ type State struct {
// Copy makes a copy of the State for mutating.
func (state State) Copy() State {
return State{
Version: state.Version,
ChainID: state.ChainID,
@ -114,9 +110,18 @@ func (state State) Equals(state2 State) bool {
return bytes.Equal(sbz, s2bz)
}
// Bytes serializes the State using go-amino.
// Bytes serializes the State using protobuf.
// It panics if either casting to protobuf or serialization fails.
func (state State) Bytes() []byte {
return cdc.MustMarshalBinaryBare(state)
sm, err := state.ToProto()
if err != nil {
panic(err)
}
bz, err := proto.Marshal(sm)
if err != nil {
panic(err)
}
return bz
}
// IsEmpty returns true if the State is equal to the empty State.
@ -124,6 +129,99 @@ func (state State) IsEmpty() bool {
return state.Validators == nil // XXX can't compare to Empty
}
//ToProto takes the local state type and returns the equivalent proto type
func (state *State) ToProto() (*tmstate.State, error) {
if state == nil {
return nil, errors.New("state is nil")
}
sm := new(tmstate.State)
sm.Version = state.Version
sm.ChainID = state.ChainID
sm.LastBlockHeight = state.LastBlockHeight
sm.LastBlockID = state.LastBlockID.ToProto()
sm.LastBlockTime = state.LastBlockTime
vals, err := state.Validators.ToProto()
if err != nil {
return nil, err
}
sm.Validators = vals
nVals, err := state.NextValidators.ToProto()
if err != nil {
return nil, err
}
sm.NextValidators = nVals
if state.LastBlockHeight >= 1 { // At Block 1 LastValidators is nil
lVals, err := state.LastValidators.ToProto()
if err != nil {
return nil, err
}
sm.LastValidators = lVals
}
sm.LastHeightValidatorsChanged = state.LastHeightValidatorsChanged
sm.ConsensusParams = state.ConsensusParams
sm.LastHeightConsensusParamsChanged = state.LastHeightConsensusParamsChanged
sm.LastResultsHash = state.LastResultsHash
sm.AppHash = state.AppHash
return sm, nil
}
// StateFromProto takes a state proto message & returns the local state type
func StateFromProto(pb *tmstate.State) (*State, error) { //nolint:golint
if pb == nil {
return nil, errors.New("nil State")
}
state := new(State)
state.Version = pb.Version
state.ChainID = pb.ChainID
bi, err := types.BlockIDFromProto(&pb.LastBlockID)
if err != nil {
return nil, err
}
state.LastBlockID = *bi
state.LastBlockHeight = pb.LastBlockHeight
state.LastBlockTime = pb.LastBlockTime
vals, err := types.ValidatorSetFromProto(pb.Validators)
if err != nil {
return nil, err
}
state.Validators = vals
nVals, err := types.ValidatorSetFromProto(pb.NextValidators)
if err != nil {
return nil, err
}
state.NextValidators = nVals
if state.LastBlockHeight >= 1 { // At Block 1 LastValidators is nil
lVals, err := types.ValidatorSetFromProto(pb.LastValidators)
if err != nil {
return nil, err
}
state.LastValidators = lVals
} else {
state.LastValidators = types.NewValidatorSet(nil)
}
state.LastHeightValidatorsChanged = pb.LastHeightValidatorsChanged
state.ConsensusParams = pb.ConsensusParams
state.LastHeightConsensusParamsChanged = pb.LastHeightConsensusParamsChanged
state.LastResultsHash = pb.LastResultsHash
state.AppHash = pb.AppHash
return state, nil
}
//------------------------------------------------------------------------
// Create a block from the latest state


+ 59
- 15
state/state_test.go View File

@ -18,6 +18,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto/ed25519"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
@ -49,6 +50,7 @@ func TestStateCopy(t *testing.T) {
stateCopy, state))
stateCopy.LastBlockHeight++
stateCopy.LastValidators = state.Validators
assert.False(state.Equals(stateCopy), fmt.Sprintf(`expected states to be different. got same
%v`, state))
}
@ -73,6 +75,7 @@ func TestStateSaveLoad(t *testing.T) {
assert := assert.New(t)
state.LastBlockHeight++
state.LastValidators = state.Validators
sm.SaveState(stateDB, state)
loadedState := sm.LoadState(stateDB)
@ -91,7 +94,11 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
// Build mock responses.
block := makeBlock(state, 2)
abciResponses := sm.NewABCIResponses(block)
abciResponses := new(tmstate.ABCIResponses)
dtxs := make([]*abci.ResponseDeliverTx, 2)
abciResponses.DeliverTxs = dtxs
abciResponses.DeliverTxs[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Events: nil}
abciResponses.DeliverTxs[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Events: nil}
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{
@ -148,6 +155,10 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
nil,
nil,
},
4: {
[]*abci.ResponseDeliverTx{nil},
nil,
},
}
// Query all before, this should return error.
@ -160,7 +171,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
// Add all cases.
for i, tc := range cases {
h := int64(i + 1) // last block height, one below what we save
responses := &sm.ABCIResponses{
responses := &tmstate.ABCIResponses{
DeliverTxs: tc.added,
EndBlock: &abci.ResponseEndBlock{},
}
@ -172,7 +183,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
h := int64(i + 1)
res, err := sm.LoadABCIResponses(stateDB, h)
assert.NoError(err, "%d", i)
assert.Equal(tc.expected.Hash(), res.ResultsHash(), "%d", i)
assert.Equal(tc.expected.Hash(), sm.ABCIResponsesResultsHash(*res), "%d", i)
}
}
@ -407,7 +418,7 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) {
block := makeBlock(state, state.LastBlockHeight+1)
blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()}
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -518,7 +529,7 @@ func TestProposerPriorityProposerAlternates(t *testing.T) {
block := makeBlock(state, state.LastBlockHeight+1)
blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()}
// no updates:
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -618,7 +629,7 @@ func TestProposerPriorityProposerAlternates(t *testing.T) {
// no changes in voting power and both validators have same voting power
// -> proposers should alternate:
oldState := updatedState3
abciResponses = &sm.ABCIResponses{
abciResponses = &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -633,7 +644,7 @@ func TestProposerPriorityProposerAlternates(t *testing.T) {
for i := 0; i < 1000; i++ {
// no validator updates:
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -690,7 +701,7 @@ func TestLargeGenesisValidator(t *testing.T) {
oldState := state
for i := 0; i < 10; i++ {
// no updates:
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -719,7 +730,7 @@ func TestLargeGenesisValidator(t *testing.T) {
firstAddedVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(firstAddedValPubKey), Power: firstAddedValVotingPower}
validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal})
assert.NoError(t, err)
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}},
}
block := makeBlock(oldState, oldState.LastBlockHeight+1)
@ -730,7 +741,7 @@ func TestLargeGenesisValidator(t *testing.T) {
lastState := updatedState
for i := 0; i < 200; i++ {
// no updates:
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -764,7 +775,7 @@ func TestLargeGenesisValidator(t *testing.T) {
validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{addedVal})
assert.NoError(t, err)
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}},
}
block := makeBlock(oldState, oldState.LastBlockHeight+1)
@ -776,7 +787,7 @@ func TestLargeGenesisValidator(t *testing.T) {
// remove genesis validator:
removeGenesisVal := abci.ValidatorUpdate{PubKey: types.TM2PB.PubKey(genesisPubKey), Power: 0}
abciResponses = &sm.ABCIResponses{
abciResponses = &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}},
}
block = makeBlock(oldState, oldState.LastBlockHeight+1)
@ -794,7 +805,7 @@ func TestLargeGenesisValidator(t *testing.T) {
count := 0
isProposerUnchanged := true
for isProposerUnchanged {
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -817,7 +828,7 @@ func TestLargeGenesisValidator(t *testing.T) {
proposers := make([]*types.Validator, numVals)
for i := 0; i < 100; i++ {
// no updates:
abciResponses := &sm.ABCIResponses{
abciResponses := &tmstate.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
@ -980,7 +991,7 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
for _, testCase := range testCases {
p, err := sm.LoadConsensusParams(stateDB, 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.EqualValues(t, testCase.params, p, fmt.Sprintf(`unexpected consensus params at
height %d`, testCase.height))
}
}
@ -1019,3 +1030,36 @@ func TestApplyUpdates(t *testing.T) {
assert.Equal(t, tc.expected, res, "case %d", i)
}
}
func TestStateProto(t *testing.T) {
tearDown, _, state := setupTestCase(t)
defer tearDown(t)
tc := []struct {
testName string
state *sm.State
expPass bool
}{
{"empty state", &sm.State{}, false},
{"nil failure state", nil, false},
{"success state", &state, true},
}
for _, tt := range tc {
tt := tt
pbs, err := tt.state.ToProto()
if !tt.expPass {
assert.Error(t, err)
} else {
assert.NoError(t, err, tt.testName)
}
smt, err := sm.StateFromProto(pbs)
if tt.expPass {
require.NoError(t, err, tt.testName)
require.Equal(t, tt.state, smt, tt.testName)
} else {
require.Error(t, err, tt.testName)
}
}
}

+ 104
- 74
state/store.go View File

@ -3,11 +3,13 @@ package state
import (
"fmt"
"github.com/gogo/protobuf/proto"
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
tmmath "github.com/tendermint/tendermint/libs/math"
tmos "github.com/tendermint/tendermint/libs/os"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
"github.com/tendermint/tendermint/types"
)
@ -56,6 +58,7 @@ func LoadStateFromDBOrGenesisFile(stateDB dbm.DB, genesisFilePath string) (State
// to the database.
func LoadStateFromDBOrGenesisDoc(stateDB dbm.DB, genesisDoc *types.GenesisDoc) (State, error) {
state := LoadState(stateDB)
if state.IsEmpty() {
var err error
state, err = MakeGenesisState(genesisDoc)
@ -82,15 +85,21 @@ func loadState(db dbm.DB, key []byte) (state State) {
return state
}
err = cdc.UnmarshalBinaryBare(buf, &state)
sp := new(tmstate.State)
err = proto.Unmarshal(buf, sp)
if err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
tmos.Exit(fmt.Sprintf(`LoadState: Data has been corrupted or its spec has changed:
%v\n`, err))
%v\n`, err))
}
// TODO: ensure that buf is completely read.
return state
sm, err := StateFromProto(sp)
if err != nil {
panic(err)
}
return *sm
}
// SaveState persists the State, the ValidatorsInfo, and the ConsensusParamsInfo to the database.
@ -110,6 +119,7 @@ func saveState(db dbm.DB, state State, key []byte) {
}
// Save next validators.
saveValidatorsInfo(db, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
// Save next consensus params.
saveConsensusParamsInfo(db, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams)
err := db.SetSync(key, state.Bytes())
@ -130,15 +140,6 @@ func BootstrapState(db dbm.DB, state State) error {
//------------------------------------------------------------------------
// 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 {
DeliverTxs []*abci.ResponseDeliverTx `json:"deliver_txs"`
EndBlock *abci.ResponseEndBlock `json:"end_block"`
BeginBlock *abci.ResponseBeginBlock `json:"begin_block"`
}
// PruneStates deletes states between the given heights (including from, excluding to). It is not
// guaranteed to delete all states, since the last checkpointed state and states being pointed to by
// e.g. `LastHeightChanged` must remain. The state at to must also exist.
@ -187,12 +188,25 @@ func PruneStates(db dbm.DB, from int64, to int64) error {
if keepVals[h] {
v := loadValidatorsInfo(db, h)
if v.ValidatorSet == nil {
v.ValidatorSet, err = LoadValidators(db, h)
vip, err := LoadValidators(db, h)
if err != nil {
return err
}
pvi, err := vip.ToProto()
if err != nil {
return err
}
v.ValidatorSet = pvi
v.LastHeightChanged = h
batch.Set(calcValidatorsKey(h), v.Bytes())
bz, err := v.Marshal()
if err != nil {
return err
}
batch.Set(calcValidatorsKey(h), bz)
}
} else {
batch.Delete(calcValidatorsKey(h))
@ -206,7 +220,11 @@ func PruneStates(db dbm.DB, from int64, to int64) error {
return err
}
p.LastHeightChanged = h
batch.Set(calcConsensusParamsKey(h), p.Bytes())
bz, err := p.Marshal()
if err != nil {
return err
}
batch.Set(calcConsensusParamsKey(h), bz)
}
} else {
batch.Delete(calcConsensusParamsKey(h))
@ -235,42 +253,27 @@ func PruneStates(db dbm.DB, from int64, to int64) error {
return nil
}
// NewABCIResponses returns a new ABCIResponses
func NewABCIResponses(block *types.Block) *ABCIResponses {
resDeliverTxs := make([]*abci.ResponseDeliverTx, len(block.Data.Txs))
if len(block.Data.Txs) == 0 {
// This makes Amino encoding/decoding consistent.
resDeliverTxs = nil
}
return &ABCIResponses{
DeliverTxs: resDeliverTxs,
}
}
// Bytes serializes the ABCIResponse using go-amino.
func (arz *ABCIResponses) Bytes() []byte {
return cdc.MustMarshalBinaryBare(arz)
}
func (arz *ABCIResponses) ResultsHash() []byte {
results := types.NewResults(arz.DeliverTxs)
// ABCIResponsesResultsHash returns the merkle hash of the deliverTxs within ABCIResponses
func ABCIResponsesResultsHash(ar tmstate.ABCIResponses) []byte {
results := types.NewResults(ar.DeliverTxs)
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) {
func LoadABCIResponses(db dbm.DB, height int64) (*tmstate.ABCIResponses, error) {
buf, err := db.Get(calcABCIResponsesKey(height))
if err != nil {
return nil, err
}
if len(buf) == 0 {
return nil, ErrNoABCIResponsesForHeight{height}
}
abciResponses := new(ABCIResponses)
err = cdc.UnmarshalBinaryBare(buf, abciResponses)
abciResponses := new(tmstate.ABCIResponses)
err = abciResponses.Unmarshal(buf)
if err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
tmos.Exit(fmt.Sprintf(`LoadABCIResponses: Data has been corrupted or its spec has
@ -287,22 +290,24 @@ func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) {
// Merkle proofs.
//
// Exposed for testing.
func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
db.SetSync(calcABCIResponsesKey(height), abciResponses.Bytes())
}
//-----------------------------------------------------------------------------
func SaveABCIResponses(db dbm.DB, height int64, abciResponses *tmstate.ABCIResponses) {
var dtxs []*abci.ResponseDeliverTx
//strip nil values,
for _, tx := range abciResponses.DeliverTxs {
if tx != nil {
dtxs = append(dtxs, tx)
}
}
abciResponses.DeliverTxs = dtxs
// ValidatorsInfo represents the latest validator set, or the last height it changed
type ValidatorsInfo struct {
ValidatorSet *types.ValidatorSet
LastHeightChanged int64
bz, err := abciResponses.Marshal()
if err != nil {
panic(err)
}
db.SetSync(calcABCIResponsesKey(height), bz)
}
// Bytes serializes the ValidatorsInfo using go-amino.
func (valInfo *ValidatorsInfo) Bytes() []byte {
return cdc.MustMarshalBinaryBare(valInfo)
}
//-----------------------------------------------------------------------------
// LoadValidators loads the ValidatorSet for a given height.
// Returns ErrNoValSetForHeight if the validator set can't be found for this height.
@ -322,11 +327,28 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) {
),
)
}
valInfo2.ValidatorSet.IncrementProposerPriority(tmmath.SafeConvertInt32(height - lastStoredHeight)) // mutate
vs, err := types.ValidatorSetFromProto(valInfo2.ValidatorSet)
if err != nil {
return nil, err
}
vs.IncrementProposerPriority(tmmath.SafeConvertInt32(height - lastStoredHeight)) // mutate
vi2, err := vs.ToProto()
if err != nil {
return nil, err
}
valInfo2.ValidatorSet = vi2
valInfo = valInfo2
}
return valInfo.ValidatorSet, nil
vip, err := types.ValidatorSetFromProto(valInfo.ValidatorSet)
if err != nil {
return nil, err
}
return vip, nil
}
func lastStoredHeightFor(height, lastHeightChanged int64) int64 {
@ -335,17 +357,18 @@ func lastStoredHeightFor(height, lastHeightChanged int64) int64 {
}
// CONTRACT: Returned ValidatorsInfo can be mutated.
func loadValidatorsInfo(db dbm.DB, height int64) *ValidatorsInfo {
func loadValidatorsInfo(db dbm.DB, height int64) *tmstate.ValidatorsInfo {
buf, err := db.Get(calcValidatorsKey(height))
if err != nil {
panic(err)
}
if len(buf) == 0 {
return nil
}
v := new(ValidatorsInfo)
err = cdc.UnmarshalBinaryBare(buf, v)
v := new(tmstate.ValidatorsInfo)
err = v.Unmarshal(buf)
if err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
tmos.Exit(fmt.Sprintf(`LoadValidators: Data has been corrupted or its spec has changed:
@ -365,29 +388,30 @@ func saveValidatorsInfo(db dbm.DB, height, lastHeightChanged int64, valSet *type
if lastHeightChanged > height {
panic("LastHeightChanged cannot be greater than ValidatorsInfo height")
}
valInfo := &ValidatorsInfo{
valInfo := &tmstate.ValidatorsInfo{
LastHeightChanged: lastHeightChanged,
}
// Only persist validator set if it was updated or checkpoint height (see
// valSetCheckpointInterval) is reached.
if height == lastHeightChanged || height%valSetCheckpointInterval == 0 {
valInfo.ValidatorSet = valSet
pv, err := valSet.ToProto()
if err != nil {
panic(err)
}
valInfo.ValidatorSet = pv
}
db.Set(calcValidatorsKey(height), valInfo.Bytes())
bz, err := valInfo.Marshal()
if err != nil {
panic(err)
}
db.Set(calcValidatorsKey(height), bz)
}
//-----------------------------------------------------------------------------
// ConsensusParamsInfo represents the latest consensus params, or the last height it changed
type ConsensusParamsInfo struct {
ConsensusParams tmproto.ConsensusParams
LastHeightChanged int64
}
// Bytes serializes the ConsensusParamsInfo using go-amino.
func (params ConsensusParamsInfo) Bytes() []byte {
return cdc.MustMarshalBinaryBare(params)
}
// LoadConsensusParams loads the ConsensusParams for a given height.
func LoadConsensusParams(db dbm.DB, height int64) (tmproto.ConsensusParams, error) {
@ -409,13 +433,14 @@ func LoadConsensusParams(db dbm.DB, height int64) (tmproto.ConsensusParams, erro
),
)
}
paramsInfo = paramsInfo2
}
return paramsInfo.ConsensusParams, nil
}
func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo {
func loadConsensusParamsInfo(db dbm.DB, height int64) *tmstate.ConsensusParamsInfo {
buf, err := db.Get(calcConsensusParamsKey(height))
if err != nil {
panic(err)
@ -424,9 +449,8 @@ func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo {
return nil
}
paramsInfo := new(ConsensusParamsInfo)
err = cdc.UnmarshalBinaryBare(buf, paramsInfo)
if err != nil {
paramsInfo := new(tmstate.ConsensusParamsInfo)
if err = paramsInfo.Unmarshal(buf); err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
tmos.Exit(fmt.Sprintf(`LoadConsensusParams: Data has been corrupted or its spec has changed:
%v\n`, err))
@ -441,11 +465,17 @@ func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo {
// 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 tmproto.ConsensusParams) {
paramsInfo := &ConsensusParamsInfo{
paramsInfo := &tmstate.ConsensusParamsInfo{
LastHeightChanged: changeHeight,
}
if changeHeight == nextHeight {
paramsInfo.ConsensusParams = params
}
db.Set(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes())
bz, err := paramsInfo.Marshal()
if err != nil {
panic(err)
}
db.Set(calcConsensusParamsKey(nextHeight), bz)
}

+ 21
- 12
state/store_test.go View File

@ -10,7 +10,10 @@ import (
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto/ed25519"
tmstate "github.com/tendermint/tendermint/proto/state"
tmproto "github.com/tendermint/tendermint/proto/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
@ -48,6 +51,7 @@ func BenchmarkLoadValidators(b *testing.B) {
if err != nil {
b.Fatal(err)
}
state.Validators = genValSet(valSetSize)
state.NextValidators = state.Validators.CopyIncrementProposerPriority(1)
sm.SaveState(stateDB, state)
@ -91,10 +95,11 @@ func TestPruneStates(t *testing.T) {
tc := tc
t.Run(name, func(t *testing.T) {
db := dbm.NewMemDB()
pk := ed25519.GenPrivKey().PubKey()
// Generate a bunch of state data. Validators change for heights ending with 3, and
// parameters when ending with 5.
validator := &types.Validator{Address: []byte{1, 2, 3}, VotingPower: 100}
validator := &types.Validator{Address: []byte{1, 2, 3}, VotingPower: 100, PubKey: pk}
validatorSet := &types.ValidatorSet{
Validators: []*types.Validator{validator},
Proposer: validator,
@ -110,7 +115,7 @@ func TestPruneStates(t *testing.T) {
paramsChanged = h
}
sm.SaveState(db, sm.State{
state := sm.State{
LastBlockHeight: h - 1,
Validators: validatorSet,
NextValidators: validatorSet,
@ -119,17 +124,21 @@ func TestPruneStates(t *testing.T) {
},
LastHeightValidatorsChanged: valsChanged,
LastHeightConsensusParamsChanged: paramsChanged,
})
sm.SaveABCIResponses(db, h, sm.NewABCIResponses(&types.Block{
Header: types.Header{Height: h},
Data: types.Data{
Txs: types.Txs{
[]byte{1},
[]byte{2},
[]byte{3},
},
}
if state.LastBlockHeight >= 1 {
state.LastValidators = state.Validators
}
sm.SaveState(db, state)
sm.SaveABCIResponses(db, h, &tmstate.ABCIResponses{
DeliverTxs: []*abci.ResponseDeliverTx{
{Data: []byte{1}},
{Data: []byte{2}},
{Data: []byte{3}},
},
}))
})
}
// Test assertions


+ 0
- 3
state/validation.go View File

@ -40,7 +40,6 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
block.Height,
)
}
// Validate prev block info.
if !block.LastBlockID.Equals(state.LastBlockID) {
return fmt.Errorf("wrong Block.Header.LastBlockID. Expected %v, got %v",
@ -103,7 +102,6 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
state.LastBlockTime,
)
}
medianTime := MedianTime(block.LastCommit, state.LastValidators)
if !block.Time.Equal(medianTime) {
return fmt.Errorf("invalid block time. Expected %v, got %v",
@ -199,7 +197,6 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence, commit
state.LastBlockTime.Add(evidenceParams.MaxAgeDuration),
)
}
if ev, ok := evidence.(*types.LunaticValidatorEvidence); ok {
if err := ev.VerifyHeader(committedHeader); err != nil {
return err


+ 3
- 2
statesync/stateprovider.go View File

@ -14,6 +14,7 @@ import (
lighthttp "github.com/tendermint/tendermint/light/provider/http"
lightrpc "github.com/tendermint/tendermint/light/rpc"
lightdb "github.com/tendermint/tendermint/light/store/db"
tmstate "github.com/tendermint/tendermint/proto/state"
rpchttp "github.com/tendermint/tendermint/rpc/client/http"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
@ -36,14 +37,14 @@ type StateProvider interface {
type lightClientStateProvider struct {
sync.Mutex // light.Client is not concurrency-safe
lc *light.Client
version sm.Version
version tmstate.Version
providers map[lightprovider.Provider]string
}
// NewLightClientStateProvider creates a new StateProvider using a light client and RPC clients.
func NewLightClientStateProvider(
chainID string,
version sm.Version,
version tmstate.Version,
servers []string,
trustOptions light.TrustOptions,
logger log.Logger,


+ 2
- 1
statesync/syncer_test.go View File

@ -14,6 +14,7 @@ import (
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
p2pmocks "github.com/tendermint/tendermint/p2p/mocks"
tmstate "github.com/tendermint/tendermint/proto/state"
ssproto "github.com/tendermint/tendermint/proto/statesync"
tmversion "github.com/tendermint/tendermint/proto/version"
"github.com/tendermint/tendermint/proxy"
@ -44,7 +45,7 @@ func simplePeer(id string) *p2pmocks.Peer {
func TestSyncer_SyncAny(t *testing.T) {
state := sm.State{
ChainID: "chain",
Version: sm.Version{
Version: tmstate.Version{
Consensus: tmversion.Consensus{
Block: version.BlockProtocol,
App: 0,


Loading…
Cancel
Save