package client import ( "errors" "fmt" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" abci "github.com/cometbft/cometbft/abci/types" clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types" ibcexported "github.com/cosmos/ibc-go/v10/modules/core/exported" ) // QueryTendermintProof performs an ABCI query with the given key and returns // the value of the query, the proto encoded merkle proof, and the height of // the Tendermint block containing the state root. The desired tendermint height // to perform the query should be set in the client context. The query will be // performed at one below this height (at the IAVL version) in order to obtain // the correct merkle proof. Proof queries at height less than or equal to 2 are // not supported. Queries with a client context height of 0 will perform a query // at the latest state available. // Issue: https://github.com/cosmos/cosmos-sdk/issues/6567 func QueryTendermintProof(clientCtx client.Context, key []byte) ([]byte, []byte, clienttypes.Height, error) { height := clientCtx.Height // ABCI queries at heights 1, 2 or less than or equal to 0 are not supported. // Base app does not support queries for height less than or equal to 1. // Therefore, a query at height 2 would be equivalent to a query at height 3. // A height of 0 will query with the latest state. if height != 0 && height <= 2 { return nil, nil, clienttypes.Height{}, errors.New("proof queries at height <= 2 are not supported") } // Use the IAVL height if a valid tendermint height is passed in. // A height of 0 will query with the latest state. if height != 0 { height-- } req := abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", ibcexported.StoreKey), Height: height, Data: key, Prove: true, } res, err := clientCtx.QueryABCI(req) if err != nil { return nil, nil, clienttypes.Height{}, err } merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) if err != nil { return nil, nil, clienttypes.Height{}, err } cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) proofBz, err := cdc.Marshal(&merkleProof) if err != nil { return nil, nil, clienttypes.Height{}, err } revision := clienttypes.ParseChainID(clientCtx.ChainID) return res.Value, proofBz, clienttypes.NewHeight(revision, uint64(res.Height)+1), nil }