diff --git a/config/config.go b/config/config.go index e360392ee..c8f4b3a88 100644 --- a/config/config.go +++ b/config/config.go @@ -557,7 +557,7 @@ type RPCConfig struct { // Set to true to enable the /BlockResults query. Saving ABCI Responses is also necessary // to reindex events used in the command line - PersistABCIResponses bool `mapstructure:"persist-abci-responses"` + DiscardABCIResponses bool `mapstructure:"persist-abci-responses"` } // DefaultRPCConfig returns a default configuration for the RPC server @@ -584,7 +584,7 @@ func DefaultRPCConfig() *RPCConfig { TLSCertFile: "", TLSKeyFile: "", - PersistABCIResponses: false, + DiscardABCIResponses: true, } } diff --git a/internal/state/errors.go b/internal/state/errors.go index 6e0cdfa47..38c581f7d 100644 --- a/internal/state/errors.go +++ b/internal/state/errors.go @@ -1,6 +1,9 @@ package state -import "fmt" +import ( + "errors" + "fmt" +) type ( ErrInvalidBlock error @@ -99,3 +102,5 @@ func (e ErrNoConsensusParamsForHeight) Error() string { func (e ErrNoABCIResponsesForHeight) Error() string { return fmt.Sprintf("could not find results for height #%d", e.Height) } + +var ErrABCIResponsesNotPersisted = errors.New("node is not persisting abci responses") diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 0cedebb00..bf5069873 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -111,7 +111,7 @@ func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValida }) stateDB := dbm.NewMemDB() - stateStore := sm.NewStore(stateDB) + stateStore := sm.NewStore(stateDB, false) if err := stateStore.Save(s); err != nil { panic(err) } diff --git a/internal/state/store.go b/internal/state/store.go index 1a2ddb944..b7f6d07a9 100644 --- a/internal/state/store.go +++ b/internal/state/store.go @@ -110,16 +110,16 @@ type Store interface { type dbStore struct { db dbm.DB - // persistABCIResponses determines if all + // discardABCIResponses determines if all // ABCI responses are persisted or just the last - persistABCIResponses bool + discardABCIResponses bool } var _ Store = (*dbStore)(nil) // NewStore creates the dbStore of the state pkg. -func NewStore(db dbm.DB, persistABCIResponses bool) Store { - return dbStore{db, persistABCIResponses} +func NewStore(db dbm.DB, discardABCIResponses bool) Store { + return dbStore{db, discardABCIResponses} } // LoadState loads the State from the database. @@ -420,22 +420,19 @@ func ABCIResponsesResultsHash(ar *tmstate.ABCIResponses) []byte { } // LoadABCIResponses loads the ABCIResponses for the given height from the -// database. If not found, ErrNoABCIResponsesForHeight is returned. -// -// 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. +// database. If the node has DiscardABCIResponses set to true, ErrABCIResponsesNotPersisted +// is persisted. If not found, ErrNoABCIResponsesForHeight is returned. func (store dbStore) LoadABCIResponses(height int64) (*tmstate.ABCIResponses, error) { - if !store.persistABCIResponses { - return nil, errors.New("this is not supported") + if !store.discardABCIResponses { + return nil, ErrABCIResponsesNotPersisted } - + buf, err := store.db.Get(abciResponsesKey(height)) if err != nil { return nil, err } - if len(buf) == 0 { + if len(buf) == 0 { return nil, ErrNoABCIResponsesForHeight{height} } abciResponses := new(tmstate.ABCIResponses) @@ -450,6 +447,21 @@ func (store dbStore) LoadABCIResponses(height int64) (*tmstate.ABCIResponses, er return abciResponses, nil } +// LoadLastABCIResponses loads the last ABCI response specifically after a crash +// We conduct a sanity check here which compares the height from the last ABICResponse to the +// height that is given +// +// This is used 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 (store dbStore) LoadLastABCIResponse(height int64) (*tmstate.ABCIResponses, error) { + bz, err := store.db.Get(lastABCIResponseKey()) + abciResponse := new(tmstate.ABCIResponses) + err = abciResponses.Unmarshal(bz) + + return abciResponse, 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 @@ -472,9 +484,9 @@ func (store dbStore) SaveABCIResponses(height int64, abciResponses *tmstate.ABCI return err } - // If the flag is true then we save the ABCIResponse. This can be used for the /BlockResults + // If the flag is false then we save the ABCIResponse. This can be used for the /BlockResults // query or to reindex an event using the command line. - if store.persistABCIResponses { + if !store.discardABCIResponses { if err := store.db.Set(abciResponsesKey(height), bz); err != nil { return err } @@ -485,6 +497,10 @@ func (store dbStore) SaveABCIResponses(height int64, abciResponses *tmstate.ABCI return store.db.SetSync(lastABCIResponseKey(), bz) } +type ResponsesInfo struct { + abcu +} + // SaveValidatorSets is used to save the validator set over multiple heights. // It is exposed so that a backfill operation during state sync can populate // the store with the necessary amount of validator sets to verify any evidence diff --git a/node/node.go b/node/node.go index b9ddd267b..e7e896bc3 100644 --- a/node/node.go +++ b/node/node.go @@ -139,7 +139,7 @@ func makeNode(cfg *config.Config, } closers = append(closers, dbCloser) - stateStore := sm.NewStore(stateDB, cfg.RPC.PersistABCIResponses) + stateStore := sm.NewStore(stateDB, cfg.RPC.DiscardABCIResponses) genDoc, err := genesisDocProvider() if err != nil { diff --git a/node/node_test.go b/node/node_test.go index 305f9b873..d82110ef5 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -232,7 +232,7 @@ func TestCreateProposalBlock(t *testing.T) { const height int64 = 1 state, stateDB, privVals := state(1, height) - stateStore := sm.NewStore(stateDB) + stateStore := sm.NewStore(stateDB, false) maxBytes := 16384 const partSize uint32 = 256 maxEvidenceBytes := int64(maxBytes / 2) @@ -325,7 +325,7 @@ func TestMaxTxsProposalBlockSize(t *testing.T) { const height int64 = 1 state, stateDB, _ := state(1, height) - stateStore := sm.NewStore(stateDB) + stateStore := sm.NewStore(stateDB, false) blockStore := store.NewBlockStore(dbm.NewMemDB()) const maxBytes int64 = 16384 const partSize uint32 = 256 @@ -387,7 +387,7 @@ func TestMaxProposalBlockSize(t *testing.T) { logger := log.TestingLogger() state, stateDB, _ := state(types.MaxVotesCount, int64(1)) - stateStore := sm.NewStore(stateDB) + stateStore := sm.NewStore(stateDB, false) blockStore := store.NewBlockStore(dbm.NewMemDB()) const maxBytes int64 = 1024 * 1024 * 2 state.ConsensusParams.Block.MaxBytes = maxBytes @@ -625,7 +625,7 @@ func state(nVals int, height int64) (sm.State, dbm.DB, []types.PrivValidator) { // save validators to db for 2 heights stateDB := dbm.NewMemDB() - stateStore := sm.NewStore(stateDB) + stateStore := sm.NewStore(stateDB, false) if err := stateStore.Save(s); err != nil { panic(err) } @@ -648,7 +648,7 @@ func loadStatefromGenesis(t *testing.T) sm.State { t.Helper() stateDB := dbm.NewMemDB() - stateStore := sm.NewStore(stateDB) + stateStore := sm.NewStore(stateDB, false) cfg, err := config.ResetTestRoot("load_state_from_genesis") require.NoError(t, err) diff --git a/node/setup.go b/node/setup.go index 28a61a0d4..608f0030c 100644 --- a/node/setup.go +++ b/node/setup.go @@ -298,7 +298,7 @@ func createEvidenceReactor( logger = logger.With("module", "evidence") reactorShim := p2p.NewReactorShim(logger, "EvidenceShim", evidence.ChannelShims) - evidencePool, err := evidence.NewPool(logger, evidenceDB, sm.NewStore(stateDB), blockStore) + evidencePool, err := evidence.NewPool(logger, evidenceDB, sm.NewStore(stateDB, cfg.RPC.DiscardABCIResponses), blockStore) if err != nil { return nil, nil, nil, fmt.Errorf("creating evidence pool: %w", err) } diff --git a/proto/tendermint/state/types.proto b/proto/tendermint/state/types.proto index 919da91e5..a1a248842 100644 --- a/proto/tendermint/state/types.proto +++ b/proto/tendermint/state/types.proto @@ -32,6 +32,10 @@ message ConsensusParamsInfo { int64 last_height_changed = 2; } +message ResponsesInfo { + ABCIResponses abc +} + message Version { tendermint.version.Consensus consensus = 1 [(gogoproto.nullable) = false]; string software = 2;