Home

Awesome


ics: TBA title: Interchain Query stage: draft category: IBC/APP requires: 25, 26, 27 kind: instantiation author: Joe Schnetzler schnetzlerjoe@gmail.com created: 2022-01-06 modified: 2022-02-12

Synopsis

This documents aims to document the structure, plan and implementation of the Interchain Queries Module allowing for cross-chain querying of state from IBC enabled chains.

Motivation

Interchain Accounts (ICS-27) brings one of the most important features IBC offers, cross chain transactions (on-chain). Limited in this functionality is the querying of state from one chain, on another chain. Adding interchain querying via the Interchain Query module, gives unlimited flexibility to chains to build IBC enabled protocols around Interchain Accounts and beyond.

Definitions

Note: that a query in state can only have one unique key-id representation. For example, if a query with key = stakers & id = 0 is already in state, the query will fail if you try to add another query with key = stakers & id = 0. A query with key = stakers & id = 1 will succeed however (as long as that is not in state already).

Desired Properties

Technical Specification

General Design

The Querying Chain starts with the implementation of the Interchain Query Module by adding the module into their chain.

The general flow for interchain queries starts with a Cross Chain Query Request from the Querying Chain which is listened to by relayers. Upon recognition of a cross chain query, relayers utilize a ABCI Query Request to query data from the Queried Chain. Upon success, the relayer submits a MsgSubmitQueryResult to the Querying chain with the success flag as 1.

On failure of a query, relayers submit MsgSubmitQueryResult with the success flag as 0 to the Querying chain. Alternatively on timeout based on the height of the querying chain, the querying chain will submit SubmitQueryTimeoutResult with the timeout height specified.

Data Structures

A CrossChainABCIQueryRequest data type is used to specify the query. Included in this is the Path which is the path field of the query i.e: /custom/auth/account. Key is the data key to name the query i.e: pools or stakers. Id is the id of the query with each key to id being unique i.e: stakers-0 or stakers-1275 (this example follows key-id format). TimeoutHeight specifies the timeout height on the querying chain to timeout the query. Bounty is a bounty that is given to the relayer for participating in the query. ClientId is used to identify the chain of interest.

type CrossChainABCIQueryRequest struct {
	Path           string
	Key            string
	Id             string
	TimeoutHeight  uint64
	Bounty         sdk.Coin
	ClientId       string
}
type QueryResult struct {
	Data     []byte
	Key      string
	Id       string
	Height   uint64
	ClientId string
	Success  bool
	Proof    ProofOps
}
type QueryTimeoutResult struct {
	Key            string
	Id       	   string
	TimeoutHeight  string
	ClientId       string
	Proof          ProofOps
}

Keepers

func CrossChainABCIQueryRequest(
	QueryRequest CrossChainABCIQueryRequest
) {
  //Keeper to initiate interchain query request. Can be imported into any module and called as needed.
}

At the beginning of each block, the querying module checks for pending queries and if the timeout on the querying chain is hit, a timeout result is submitted to state on-chain.

func SubmitQueryTimeoutResult(
	QueryTimeout QueryTimeoutResult
) {
  //Keeper to submit a query timeout result. Applied at the beggining of each block and timedout when the querying chain hits timeout height.
}

Messages

The querying chain has messages that the relayer can submit depending on a success/failed query.

func MsgSubmitQueryResult(

) *cobra.Command {
  //Msg to submit a query result
}

The querying chain will have messages to get a list of interchain queries as well as get a query by type and id.

func MsgGetQueries(

) *cobra.Command {
  //Msg to get a list of queries
}
// Add -- max-height flag to allow for querying the highest height for a query (most recent)?
func MsgGetQuery(

) *cobra.Command {
  //Msg to get a query via id and key (i.e: id: 1 and key: OsmosisPool)
}

Events

The querying chain will emit an EmitQueryEvent which will signal the relayer to go perform an interchain query and submit the results on-chain.

func EmitQueryEvent(ctx sdk.Context, timeoutHeight exported.Height) {
	//Event to trigger query event on relayer
	ctx.EventManager().EmitEvents(sdk.Events{
		sdk.NewEvent(
		)
	})
}