cosmos / cosmjs

The Swiss Army knife to power JavaScript based client solutions ranging from Web apps/explorers over browser extensions to server-side clients like faucets/scrapers.
https://cosmos.github.io/cosmjs/
Apache License 2.0
646 stars 331 forks source link

WasmExtension queries without height #1416

Open tuloski opened 1 year ago

tuloski commented 1 year ago

With the WasmExtension for QueryClient is not possible to make a query with a specific height as it can be done with ABCIquery. And I think it's a very useful feature. I myself very often query smart contracts but get outdated data without knowing.

apolloshab commented 1 year ago

agreed that feature would be awesome. posted a similar issue here https://github.com/osmosis-labs/telescope/issues/356

dakom commented 1 year ago

I myself very often query smart contracts but get outdated data without knowing.

I've also run into this problem, though for my use case I'd prefer just knowing the height a query was actually made at, instead of specifying what it should be made at. That way I can do something like "if query height is less than or equal to the last height I got, sleep and try again"

Will open a PR to address this and take it from there... I think it's across a couple different packages

webmaster128 commented 1 year ago

This is a very valid request. The problem with this is that it affects ALL queries of ALL query extensions. Not being able to provide a hight and not getting the query height is a limitation of the API.

dakom commented 1 year ago

I started hacking around, but it would require coordination between cosmjs-types and packages here. Also didn't have permission to push a branch to cosmjs-types

@webmaster128 - this "monkey patch" is horribly ugly, but it's illustrative and does work in a pinch. Can you please advise on next steps if I can help relieve the burden of getting something like this in, if possible?

In other words, instead of doing what I did here (patching queryAbci()), I'm thinking there could be a brand new queryContractSmartAndHeight() which won't break any existing code in the wild, and passes the height all the way through - i.e. the Rpc interface would also have a new requestAndHeight() or something. Please let me know if that's unclear.

Here's my current patch, which I wouldn't advise others to do, hehe:

// client is a `SigningCosmWasmClient` or `CosmWasmClient`
// `forceGetQueryClient()` is `protected`, so bypass the type safety
monkeyPatchQuerier((client as any).forceGetQueryClient());

// this throttles stale queries
function monkeyPatchQuerier(querier: Querier) {
  const MAX_ATTEMPTS = 5
  const SLEEP_TIME_MS = 200
  const originalQueryAbci = querier.queryAbci
  let lastQueryHeight: number = -1

  querier.queryAbci = async (
    path: string,
    request: Uint8Array,
    desiredHeight?: number
  ): Promise<QueryAbciResponse> => {
    let attempts = MAX_ATTEMPTS
    while (attempts--) {
      // yes, eww
      const resp = await originalQueryAbci.bind(
        querier,
        path,
        request,
        desiredHeight
      )()

      if (desiredHeight != undefined) {
        return resp
      } else if (resp.height >= lastQueryHeight) {
        // console.log(
        //   `LOG: Querying abci at height ${resp.height} succeeded in ${
        //     MAX_ATTEMPTS - attempts
        //   } attempts.`
        // )
        lastQueryHeight = resp.height
        return resp
      } else {
        // console.log(
        //   `LOG: QUERY abci is backwards at height ${
        //     resp.height
        //   }, last height was ${lastQueryHeight}. Attempt #${
        //     MAX_ATTEMPTS - attempts
        //   } attempts.`
        // )
        await new Promise((resolve) => setTimeout(resolve, SLEEP_TIME_MS))
      }
    }

    throw new Error("Failed to query abci, stuck in historical block")
  }
}

type Querier = QueryClient &
  AuthExtension &
  BankExtension &
  TxExtension &
  WasmExtension