refactor(Store): remove abci query req and res deps from store (#16321)

This commit is contained in:
Marko 2023-05-30 17:50:23 +02:00 committed by GitHub
parent 6b37d8630e
commit d1a337eb78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 183 additions and 85 deletions

View File

@ -881,13 +881,16 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) *abci.
), app.trace)
}
// TODO: Update Query interface method accept a pointer to RequestQuery.
//
// Ref: https://github.com/cosmos/cosmos-sdk/issues/12272
resp := queryable.Query(&req)
sdkReq := storetypes.RequestQuery(req)
resp, err := queryable.Query(&sdkReq)
if err != nil {
return sdkerrors.QueryResult(err, app.trace)
}
resp.Height = req.Height
return resp
abciResp := abci.ResponseQuery(*resp)
return &abciResp
}
func handleQueryP2P(app *BaseApp, path []string) *abci.ResponseQuery {

1
go.mod
View File

@ -162,6 +162,7 @@ replace (
// TODO: remove me after collections 0.2. is released.
cosmossdk.io/collections => ./collections
cosmossdk.io/core => ./core
cosmossdk.io/store => ./store
// TODO: remove after 0.7.0 release
cosmossdk.io/x/tx => ./x/tx
)

2
go.sum
View File

@ -45,8 +45,6 @@ cosmossdk.io/log v1.1.0 h1:v0ogPHYeTzPcBTcPR1A3j1hkei4pZama8kz8LKlCMv0=
cosmossdk.io/log v1.1.0/go.mod h1:6zjroETlcDs+mm62gd8Ig7mZ+N+fVOZS91V17H+M4N4=
cosmossdk.io/math v1.0.1 h1:Qx3ifyOPaMLNH/89WeZFH268yCvU4xEcnPLu3sJqPPg=
cosmossdk.io/math v1.0.1/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k=
cosmossdk.io/store v0.1.0-alpha.1.0.20230524212735-6cabb6aa5741 h1:FkLRZDiqtcb9OSbNQULnB93W4W44zwbW1fRYZiJwGVM=
cosmossdk.io/store v0.1.0-alpha.1.0.20230524212735-6cabb6aa5741/go.mod h1:hGr2ujwG6vkDTxzwWEBU3CC38HHP9G5LPSrtHae9VR8=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=

View File

@ -27,11 +27,16 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
- [#15712](https://github.com/cosmos/cosmos-sdk/pull/15712) Add `WorkingHash` function to the store interface to get the current app hash before commit.
* [#15712](https://github.com/cosmos/cosmos-sdk/pull/15712) Add `WorkingHash` function to the store interface to get the current app hash before commit.
* [#14645](https://github.com/cosmos/cosmos-sdk/pull/14645) Add limit to the length of key and value.
* [#15683](https://github.com/cosmos/cosmos-sdk/pull/15683) `rootmulti.Store.CacheMultiStoreWithVersion` now can handle loading archival states that don't persist any of the module stores the current state has.
* [#16060](https://github.com/cosmos/cosmos-sdk/pull/16060) Support saving restoring snapshot locally.
### Api Breaking Changes
* [#16321](https://github.com/cosmos/cosmos-sdk/pull/16321) QueryInterface defines its own request and response types instead of relying on comet/abci & returns an error
## [v0.1.0-alpha.1](https://github.com/cosmos/cosmos-sdk/releases/tag/store%2Fv0.1.0-alpha.1) - 2023-03-17
### Features

View File

@ -5,7 +5,6 @@ import (
"fmt"
"io"
abci "github.com/cometbft/cometbft/abci/types"
cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/iavl"
@ -304,7 +303,7 @@ func (st *Store) Import(version int64) (*iavl.Importer, error) {
}
// Handle gatest the latest height, if height is 0
func getHeight(tree Tree, req *abci.RequestQuery) int64 {
func getHeight(tree Tree, req *types.RequestQuery) int64 {
height := req.Height
if height == 0 {
latest := tree.Version()
@ -324,18 +323,18 @@ func getHeight(tree Tree, req *abci.RequestQuery) int64 {
// If latest-1 is not present, use latest (which must be present)
// if you care to have the latest data to see a tx results, you must
// explicitly set the height you want to see
func (st *Store) Query(req *abci.RequestQuery) (res *abci.ResponseQuery) {
func (st *Store) Query(req *types.RequestQuery) (res *types.ResponseQuery, err error) {
defer st.metrics.MeasureSince("store", "iavl", "query")
if len(req.Data) == 0 {
return types.QueryResult(errorsmod.Wrap(types.ErrTxDecode, "query cannot be zero length"), false)
return &types.ResponseQuery{}, errorsmod.Wrap(types.ErrTxDecode, "query cannot be zero length")
}
tree := st.tree
// store the height we chose in the response, with 0 being changed to the
// latest height
res = &abci.ResponseQuery{
res = &types.ResponseQuery{
Height: getHeight(tree, req),
}
@ -395,10 +394,10 @@ func (st *Store) Query(req *abci.RequestQuery) (res *abci.ResponseQuery) {
res.Value = bz
default:
return types.QueryResult(errorsmod.Wrapf(types.ErrUnknownRequest, "unexpected query path: %v", req.Path), false)
return &types.ResponseQuery{}, errorsmod.Wrapf(types.ErrUnknownRequest, "unexpected query path: %v", req.Path)
}
return res
return res, err
}
// TraverseStateChanges traverses the state changes between two versions and calls the given function.

View File

@ -6,7 +6,6 @@ import (
"testing"
"cosmossdk.io/log"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/iavl"
"github.com/stretchr/testify/require"
@ -138,7 +137,8 @@ func TestGetImmutable(t *testing.T) {
require.NoError(t, err)
require.Equal(t, newStore.Get([]byte("hello")), []byte("adios"))
res := newStore.Query(&abci.RequestQuery{Data: []byte("hello"), Height: cID.Version, Path: "/key", Prove: true})
res, err := newStore.Query(&types.RequestQuery{Data: []byte("hello"), Height: cID.Version, Path: "/key", Prove: true})
require.NoError(t, err)
require.Equal(t, res.Value, []byte("adios"))
require.NotNil(t, res.ProofOps)
@ -501,11 +501,12 @@ func TestIAVLStoreQuery(t *testing.T) {
cid := iavlStore.Commit()
ver := cid.Version
query := abci.RequestQuery{Path: "/key", Data: k1, Height: ver}
querySub := abci.RequestQuery{Path: "/subspace", Data: ksub, Height: ver}
query := types.RequestQuery{Path: "/key", Data: k1, Height: ver}
querySub := types.RequestQuery{Path: "/subspace", Data: ksub, Height: ver}
// query subspace before anything set
qres := iavlStore.Query(&querySub)
qres, err := iavlStore.Query(&querySub)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, valExpSubEmpty, qres.Value)
@ -514,24 +515,28 @@ func TestIAVLStoreQuery(t *testing.T) {
iavlStore.Set(k2, v2)
// set data without commit, doesn't show up
qres = iavlStore.Query(&query)
qres, err = iavlStore.Query(&query)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Nil(t, qres.Value)
// commit it, but still don't see on old version
cid = iavlStore.Commit()
qres = iavlStore.Query(&query)
qres, err = iavlStore.Query(&query)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Nil(t, qres.Value)
// but yes on the new version
query.Height = cid.Version
qres = iavlStore.Query(&query)
qres, err = iavlStore.Query(&query)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, v1, qres.Value)
// and for the subspace
qres = iavlStore.Query(&querySub)
qres, err = iavlStore.Query(&querySub)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, valExpSub1, qres.Value)
@ -540,28 +545,33 @@ func TestIAVLStoreQuery(t *testing.T) {
cid = iavlStore.Commit()
// query will return old values, as height is fixed
qres = iavlStore.Query(&query)
qres, err = iavlStore.Query(&query)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, v1, qres.Value)
// update to latest in the query and we are happy
query.Height = cid.Version
qres = iavlStore.Query(&query)
qres, err = iavlStore.Query(&query)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, v3, qres.Value)
query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version}
query2 := types.RequestQuery{Path: "/key", Data: k2, Height: cid.Version}
qres = iavlStore.Query(&query2)
qres, err = iavlStore.Query(&query2)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, v2, qres.Value)
// and for the subspace
qres = iavlStore.Query(&querySub)
qres, err = iavlStore.Query(&querySub)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, valExpSub2, qres.Value)
// default (height 0) will show latest -1
query0 := abci.RequestQuery{Path: "/key", Data: k1}
qres = iavlStore.Query(&query0)
query0 := types.RequestQuery{Path: "/key", Data: k1}
qres, err = iavlStore.Query(&query0)
require.NoError(t, err)
require.Equal(t, uint32(0), qres.Code)
require.Equal(t, v1, qres.Value)
}

View File

@ -8,6 +8,7 @@ import (
cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
"cosmossdk.io/store/internal/kv"
"cosmossdk.io/store/internal/tree"
)
// merkleMap defines a merkle-ized tree from a map. Leave values are treated as
@ -66,7 +67,7 @@ func hashKVPairs(kvs kv.Pairs) []byte {
kvsH[i] = KVPair(kvp).Bytes()
}
return merkle.HashFromByteSlices(kvsH)
return tree.HashFromByteSlices(kvsH)
}
// ---------------------------------------------

View File

@ -0,0 +1,68 @@
package tree
import (
"crypto/sha256"
"hash"
"math/bits"
)
var (
leafPrefix = []byte{0}
innerPrefix = []byte{1}
)
// HashFromByteSlices computes a Merkle tree where the leaves are the byte slice,
// in the provided order. It follows RFC-6962.
func HashFromByteSlices(items [][]byte) []byte {
return hashFromByteSlices(sha256.New(), items)
}
func hashFromByteSlices(sha hash.Hash, items [][]byte) []byte {
switch len(items) {
case 0:
return emptyHash()
case 1:
return leafHashOpt(sha, items[0])
default:
k := getSplitPoint(int64(len(items)))
left := hashFromByteSlices(sha, items[:k])
right := hashFromByteSlices(sha, items[k:])
return innerHashOpt(sha, left, right)
}
}
// returns tmhash(0x00 || leaf)
func leafHashOpt(s hash.Hash, leaf []byte) []byte {
s.Reset()
s.Write(leafPrefix)
s.Write(leaf)
return s.Sum(nil)
}
func innerHashOpt(s hash.Hash, left, right []byte) []byte {
s.Reset()
s.Write(innerPrefix)
s.Write(left)
s.Write(right)
return s.Sum(nil)
}
// returns tmhash(<empty>)
func emptyHash() []byte {
h := sha256.Sum256([]byte{})
return h[:]
}
// getSplitPoint returns the largest power of 2 less than length
func getSplitPoint(length int64) int64 {
if length < 1 {
panic("Trying to split a tree with size < 1")
}
uLength := uint(length)
bitlen := bits.Len(uLength)
k := int64(1 << uint(bitlen-1))
if k == length {
k >>= 1
}
return k
}

View File

@ -4,13 +4,11 @@ import (
"testing"
"cosmossdk.io/log"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
"cosmossdk.io/store/iavl"
"cosmossdk.io/store/metrics"
"cosmossdk.io/store/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
)
func TestVerifyIAVLStoreQueryProof(t *testing.T) {
@ -23,11 +21,12 @@ func TestVerifyIAVLStoreQueryProof(t *testing.T) {
cid := store.Commit()
// Get Proof
res := store.Query(&abci.RequestQuery{
res, err := store.Query(&types.RequestQuery{
Path: "/key", // required path to get key/value+proof
Data: []byte("MYKEY"),
Prove: true,
})
require.NoError(t, err)
require.NotNil(t, res.ProofOps)
// Verify proof.
@ -70,16 +69,17 @@ func TestVerifyMultiStoreQueryProof(t *testing.T) {
cid := store.Commit()
// Get Proof
res := store.Query(&abci.RequestQuery{
res, err := store.Query(&types.RequestQuery{
Path: "/iavlStoreKey/key", // required path to get key/value+proof
Data: []byte("MYKEY"),
Prove: true,
})
require.NoError(t, err)
require.NotNil(t, res.ProofOps)
// Verify proof.
prt := DefaultProofRuntime()
err := prt.VerifyValue(res.ProofOps, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE"))
err = prt.VerifyValue(res.ProofOps, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE"))
require.Nil(t, err)
// Verify proof.
@ -126,11 +126,12 @@ func TestVerifyMultiStoreQueryProofAbsence(t *testing.T) {
cid := store.Commit() // Commit with empty iavl store.
// Get Proof
res := store.Query(&abci.RequestQuery{
res, err := store.Query(&types.RequestQuery{
Path: "/iavlStoreKey/key", // required path to get key/value+proof
Data: []byte("MYABSENTKEY"),
Prove: true,
})
require.NoError(t, err)
require.NotNil(t, res.ProofOps)
// Verify proof.

View File

@ -10,7 +10,6 @@ import (
"sync"
"cosmossdk.io/log"
abci "github.com/cometbft/cometbft/abci/types"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
dbm "github.com/cosmos/cosmos-db"
protoio "github.com/cosmos/gogoproto/io"
@ -726,33 +725,33 @@ func (rs *Store) GetStoreByName(name string) types.Store {
// modified to remove the substore prefix.
// Ie. `req.Path` here is `/<substore>/<path>`, and trimmed to `/<path>` for the substore.
// TODO: add proof for `multistore -> substore`.
func (rs *Store) Query(req *abci.RequestQuery) *abci.ResponseQuery {
func (rs *Store) Query(req *types.RequestQuery) (*types.ResponseQuery, error) {
path := req.Path
storeName, subpath, err := parsePath(path)
if err != nil {
return types.QueryResult(err, false)
return &types.ResponseQuery{}, err
}
store := rs.GetStoreByName(storeName)
if store == nil {
return types.QueryResult(errorsmod.Wrapf(types.ErrUnknownRequest, "no such store: %s", storeName), false)
return &types.ResponseQuery{}, errorsmod.Wrapf(types.ErrUnknownRequest, "no such store: %s", storeName)
}
queryable, ok := store.(types.Queryable)
if !ok {
return types.QueryResult(errorsmod.Wrapf(types.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store), false)
return &types.ResponseQuery{}, errorsmod.Wrapf(types.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store)
}
// trim the path and make the query
req.Path = subpath
res := queryable.Query(req)
res, err := queryable.Query(req)
if !req.Prove || !RequireProof(subpath) {
return res
return res, err
}
if res.ProofOps == nil || len(res.ProofOps.Ops) == 0 {
return types.QueryResult(errorsmod.Wrap(types.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned"), false)
return &types.ResponseQuery{}, errorsmod.Wrap(types.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")
}
// If the request's height is the latest height we've committed, then utilize
@ -765,14 +764,14 @@ func (rs *Store) Query(req *abci.RequestQuery) *abci.ResponseQuery {
} else {
commitInfo, err = rs.GetCommitInfo(res.Height)
if err != nil {
return types.QueryResult(err, false)
return &types.ResponseQuery{}, err
}
}
// Restore origin path and append proof op.
res.ProofOps.Ops = append(res.ProofOps.Ops, commitInfo.ProofOp(storeName))
return res
return res, nil
}
// SetInitialVersion sets the initial version of the IAVL tree. It is used when

View File

@ -6,8 +6,8 @@ import (
"testing"
"time"
"cosmossdk.io/errors"
"cosmossdk.io/log"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/stretchr/testify/require"
@ -456,41 +456,44 @@ func TestMultiStoreQuery(t *testing.T) {
require.Nil(t, err)
// Test bad path.
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
qres := multi.Query(&query)
require.EqualValues(t, types.ErrUnknownRequest.ABCICode(), qres.Code)
require.EqualValues(t, types.ErrUnknownRequest.Codespace(), qres.Codespace)
query := types.RequestQuery{Path: "/key", Data: k, Height: ver}
_, err = multi.Query(&query)
codespace, code, _ := errors.ABCIInfo(err, false)
require.EqualValues(t, types.ErrUnknownRequest.ABCICode(), code)
require.EqualValues(t, types.ErrUnknownRequest.Codespace(), codespace)
query.Path = "h897fy32890rf63296r92"
qres = multi.Query(&query)
require.EqualValues(t, types.ErrUnknownRequest.ABCICode(), qres.Code)
require.EqualValues(t, types.ErrUnknownRequest.Codespace(), qres.Codespace)
_, err = multi.Query(&query)
codespace, code, _ = errors.ABCIInfo(err, false)
require.EqualValues(t, types.ErrUnknownRequest.ABCICode(), code)
require.EqualValues(t, types.ErrUnknownRequest.Codespace(), codespace)
// Test invalid store name.
query.Path = "/garbage/key"
qres = multi.Query(&query)
require.EqualValues(t, types.ErrUnknownRequest.ABCICode(), qres.Code)
require.EqualValues(t, types.ErrUnknownRequest.Codespace(), qres.Codespace)
_, err = multi.Query(&query)
codespace, code, _ = errors.ABCIInfo(err, false)
require.EqualValues(t, types.ErrUnknownRequest.ABCICode(), code)
require.EqualValues(t, types.ErrUnknownRequest.Codespace(), codespace)
// Test valid query with data.
query.Path = "/store1/key"
qres = multi.Query(&query)
require.EqualValues(t, 0, qres.Code)
qres, err := multi.Query(&query)
require.NoError(t, err)
require.Equal(t, v, qres.Value)
// Test valid but empty query.
query.Path = "/store2/key"
query.Prove = true
qres = multi.Query(&query)
require.EqualValues(t, 0, qres.Code)
qres, err = multi.Query(&query)
require.NoError(t, err)
require.Nil(t, qres.Value)
// Test store2 data.
// Since we are using the request as a reference, the path will be modified.
query.Data = k2
query.Path = "/store2/key"
qres = multi.Query(&query)
require.EqualValues(t, 0, qres.Code)
qres, err = multi.Query(&query)
require.NoError(t, err)
require.Equal(t, v2, qres.Value)
}

View File

@ -2,13 +2,11 @@ package types
import (
"cosmossdk.io/log"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
)
// Context is an interface used by an App to pass context information
// needed to process store streaming requests.
type Context interface {
BlockHeader() tmproto.Header
BlockHeight() int64
Logger() log.Logger
StreamingManager() StreamingManager

View File

@ -2,7 +2,6 @@ package types
import (
"cosmossdk.io/errors"
abci "github.com/cometbft/cometbft/abci/types"
)
const StoreCodespace = "store"
@ -27,16 +26,3 @@ var (
// invalid data.
ErrInvalidRequest = errors.Register(StoreCodespace, 7, "invalid request")
)
// ABCI QueryResult
// QueryResult returns a ResponseQuery from an error. It will try to parse ABCI
// info from the error.
func QueryResult(err error, debug bool) *abci.ResponseQuery {
space, code, log := errors.ABCIInfo(err, debug)
return &abci.ResponseQuery{
Codespace: space,
Code: code,
Log: log,
}
}

View File

@ -4,7 +4,7 @@ import (
"fmt"
"io"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/proto/tendermint/crypto"
dbm "github.com/cosmos/cosmos-db"
"cosmossdk.io/store/metrics"
@ -40,7 +40,26 @@ type CommitStore interface {
//
// This is an optional, but useful extension to any CommitStore
type Queryable interface {
Query(*abci.RequestQuery) *abci.ResponseQuery
Query(*RequestQuery) (*ResponseQuery, error)
}
type RequestQuery struct {
Data []byte
Path string
Height int64
Prove bool
}
type ResponseQuery struct {
Code uint32
Log string
Info string
Index int64
Key []byte
Value []byte
ProofOps *crypto.ProofOps
Height int64
Codespace string
}
//----------------------------------------

View File

@ -160,5 +160,6 @@ replace (
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/x/tx => ../../x/tx
cosmossdk.io/store => ../../store
github.com/cosmos/cosmos-sdk => ../../
)

View File

@ -151,5 +151,6 @@ replace (
cosmossdk.io/collections => ../../collections // TODO: remove me after collections v0.2.0 is released
cosmossdk.io/core => ../../core
cosmossdk.io/x/tx => ../../x/tx
cosmossdk.io/store => ../../store
github.com/cosmos/cosmos-sdk => ../..
)

View File

@ -153,5 +153,6 @@ replace (
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/x/tx => ../tx
cosmossdk.io/store => ../../store
github.com/cosmos/cosmos-sdk => ../../.
)

View File

@ -156,6 +156,7 @@ replace (
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/x/tx => ../tx
cosmossdk.io/store => ../../store
github.com/cosmos/cosmos-sdk => ../../
)

View File

@ -156,5 +156,6 @@ replace (
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/x/tx => ../tx
cosmossdk.io/store => ../../store
github.com/cosmos/cosmos-sdk => ../../
)

View File

@ -155,6 +155,7 @@ replace (
// TODO: remove me after collections 0.2. is released.
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/store => ../../store
// TODO remove once https://github.com/cosmos/cosmos-sdk/pull/16155 is merged
github.com/cosmos/cosmos-sdk => ../..
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0

View File

@ -182,5 +182,6 @@ replace (
cosmossdk.io/collections => ../../collections
cosmossdk.io/core => ../../core
cosmossdk.io/x/tx => ../tx
cosmossdk.io/store => ../../store
github.com/cosmos/cosmos-sdk => ../../
)