Skip to content

Commit

Permalink
feat: auto-set block timestamp for historical queries (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoowonYun authored Dec 14, 2023
1 parent 876defe commit e40f08b
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 57 deletions.
16 changes: 16 additions & 0 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/cosmos/cosmos-sdk/codec"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/store/rootmulti"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -310,6 +311,11 @@ func (app *BaseApp) Commit() abci.ResponseCommit {
header := app.deliverState.ctx.BlockHeader()
retainHeight := app.GetBlockRetentionHeight(header.Height)

rms, ok := app.cms.(*rootmulti.Store)
if ok {
rms.SetCommitHeader(header)
}

// Write the DeliverTx state into branched storage and commit the MultiStore.
// The write to the DeliverTx state writes all state transitions to the root
// MultiStore (app.cms) so when Commit() is called is persists those values.
Expand Down Expand Up @@ -682,6 +688,16 @@ func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, e
cacheMS, app.checkState.ctx.BlockHeader(), true, app.logger,
).WithMinGasPrices(app.minGasPrices).WithBlockHeight(height)

if height != lastBlockHeight {
rms, ok := app.cms.(*rootmulti.Store)
if ok {
cInfo, err := rms.GetCommitInfo(height)
if cInfo != nil && err == nil {
ctx = ctx.WithBlockTime(cInfo.Timestamp)
}
}
}

return ctx, nil
}

Expand Down
1 change: 1 addition & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2965,6 +2965,7 @@ a version/height.
| ----- | ---- | ----- | ----------- |
| `version` | [int64](#int64) | | |
| `store_infos` | [StoreInfo](#cosmos.base.store.v1beta1.StoreInfo) | repeated | |
| `timestamp` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |



Expand Down
6 changes: 4 additions & 2 deletions proto/cosmos/base/store/v1beta1/commit_info.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ syntax = "proto3";
package cosmos.base.store.v1beta1;

import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";

option go_package = "github.com/cosmos/cosmos-sdk/store/types";

// CommitInfo defines commit information used by the multi-store when committing
// a version/height.
message CommitInfo {
int64 version = 1;
repeated StoreInfo store_infos = 2 [(gogoproto.nullable) = false];
int64 version = 1;
repeated StoreInfo store_infos = 2 [(gogoproto.nullable) = false];
google.protobuf.Timestamp timestamp = 3 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}

// StoreInfo defines store-specific commit information. It contains a reference
Expand Down
22 changes: 11 additions & 11 deletions proto/cosmos/base/store/v1beta1/listening.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ message StoreKVPair {
// BlockMetadata contains all the abci event data of a block
// the file streamer dump them into files together with the state changes.
message BlockMetadata {
// DeliverTx encapulate deliver tx request and response.
message DeliverTx {
tendermint.abci.RequestDeliverTx request = 1;
tendermint.abci.ResponseDeliverTx response = 2;
}
tendermint.abci.RequestBeginBlock request_begin_block = 1;
tendermint.abci.ResponseBeginBlock response_begin_block = 2;
repeated DeliverTx deliver_txs = 3;
tendermint.abci.RequestEndBlock request_end_block = 4;
tendermint.abci.ResponseEndBlock response_end_block = 5;
tendermint.abci.ResponseCommit response_commit = 6;
// DeliverTx encapulate deliver tx request and response.
message DeliverTx {
tendermint.abci.RequestDeliverTx request = 1;
tendermint.abci.ResponseDeliverTx response = 2;
}
tendermint.abci.RequestBeginBlock request_begin_block = 1;
tendermint.abci.ResponseBeginBlock response_begin_block = 2;
repeated DeliverTx deliver_txs = 3;
tendermint.abci.RequestEndBlock request_end_block = 4;
tendermint.abci.ResponseEndBlock response_end_block = 5;
tendermint.abci.ResponseCommit response_commit = 6;
}
64 changes: 40 additions & 24 deletions store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/proto/tendermint/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"

snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
Expand Down Expand Up @@ -64,6 +65,8 @@ type Store struct {
interBlockCache types.MultiStorePersistentCache

listeners map[types.StoreKey][]types.WriteListener

commitHeader tmproto.Header
}

var (
Expand Down Expand Up @@ -191,7 +194,8 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
// load old data if we are not version 0
if ver != 0 {
var err error
cInfo, err = getCommitInfo(rs.db, ver)

cInfo, err = rs.GetCommitInfo(ver)
if err != nil {
return err
}
Expand Down Expand Up @@ -399,7 +403,14 @@ func (rs *Store) Commit() types.CommitID {
version = previousHeight + 1
}

if rs.commitHeader.Height != version {
rs.logger.Debug("commit header and version mismatch", "header_height", rs.commitHeader.Height, "version", version)
}

rs.lastCommitInfo = commitStores(version, rs.stores)
rs.lastCommitInfo.Timestamp = rs.commitHeader.Time

defer flushMetadata(rs.db, version, rs.lastCommitInfo, rs.pruneHeights)

// Determine if pruneHeight height needs to be added to the list of heights to
// be pruned, where pruneHeight = (commitHeight - 1) - KeepRecent.
Expand All @@ -420,8 +431,6 @@ func (rs *Store) Commit() types.CommitID {
rs.PruneStores(true, nil)
}

flushMetadata(rs.db, version, rs.lastCommitInfo, rs.pruneHeights)

return types.CommitID{
Version: version,
Hash: rs.lastCommitInfo.Hash(),
Expand Down Expand Up @@ -620,7 +629,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery {
if res.Height == rs.lastCommitInfo.Version {
commitInfo = rs.lastCommitInfo
} else {
commitInfo, err = getCommitInfo(rs.db, res.Height)
commitInfo, err = rs.GetCommitInfo(res.Height)
if err != nil {
return sdkerrors.QueryResult(err)
}
Expand Down Expand Up @@ -937,6 +946,32 @@ func (rs *Store) RollbackToVersion(target int64) error {
return rs.LoadLatestVersion()
}

// SetCommitHeader sets the commit block header of the store.
func (rs *Store) SetCommitHeader(h tmproto.Header) {
rs.commitHeader = h
}

// GetCommitInfo attempts to retrieve CommitInfo for a given version/height. It
// will return an error if no CommitInfo exists, we fail to unmarshal the record
// or if we cannot retrieve the object from the DB.
func (rs *Store) GetCommitInfo(ver int64) (*types.CommitInfo, error) {
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver)

bz, err := rs.db.Get([]byte(cInfoKey))
if err != nil {
return nil, errors.Wrap(err, "failed to get commit info")
} else if bz == nil {
return nil, errors.New("no commit info found")
}

cInfo := &types.CommitInfo{}
if err = cInfo.Unmarshal(bz); err != nil {
return nil, errors.Wrap(err, "failed unmarshal commit info")
}

return cInfo, nil
}

type storeParams struct {
key types.StoreKey
db dbm.DB
Expand Down Expand Up @@ -994,7 +1029,7 @@ func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore
}

func (rs *Store) doProofsQuery(req abci.RequestQuery) abci.ResponseQuery {
commitInfo, err := getCommitInfo(rs.db, req.Height)
commitInfo, err := rs.GetCommitInfo(req.Height)
if err != nil {
return sdkerrors.QueryResult(err)
}
Expand All @@ -1011,25 +1046,6 @@ func (rs *Store) doProofsQuery(req abci.RequestQuery) abci.ResponseQuery {
return res
}

// Gets commitInfo from disk.
func getCommitInfo(db dbm.DB, ver int64) (*types.CommitInfo, error) {
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver)

bz, err := db.Get([]byte(cInfoKey))
if err != nil {
return nil, errors.Wrap(err, "failed to get commit info")
} else if bz == nil {
return nil, errors.New("no commit info found")
}

cInfo := &types.CommitInfo{}
if err = cInfo.Unmarshal(bz); err != nil {
return nil, errors.Wrap(err, "failed unmarshal commit info")
}

return cInfo, nil
}

func setCommitInfo(batch dbm.Batch, version int64, cInfo *types.CommitInfo) {
bz, err := cInfo.Marshal()
if err != nil {
Expand Down
99 changes: 79 additions & 20 deletions store/types/commit_info.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e40f08b

Please sign in to comment.