wrap-cli icon indicating copy to clipboard operation
wrap-cli copied to clipboard

allow wrappers to know about their URIs

Open fetsorn opened this issue 1 year ago • 7 comments

We should allow a wrapper to know about its URI.

~~Canonical uri of the wrapper should be read from wrap.info during codegen and exported as a constant in the bindings~~ ~~Also see polywrap/technical-council#69~~

We can pass an InvokeContext on every invoke, and invocables will have access to their and their caller's URI and perhaps more metadata in the future.
This will require an update to the invocation standard.

// wrapper
import { InvokeContext } from "./wrap";

function getThisUri() {
  InvokeContext.callerUri();
}
// wrapper bindings
InvokeContext {
  callerUri() {
    buffer = "thisUri".to_buf();
    __wrap_invoke_context_get_prop_size(&buffer, buffer.size) => value_size
    value = new Buffer(value_size)
    __wrap_invoke_context_load_prop(&value, value.size) => boolean
    value.to_str() // "wrap://..."
  }
}
// plugin bindings
interface InvokeContext {
  contextId: string;
  callerUri?: Uri;
  thisUri: Uri;
}

interface PluginContext extends InvokeContext {
  client: Client;
}

abstract pluginMethod(
  args: Args_pluginMethod,
  context: PluginContext
): MaybeAsync<type>;

fetsorn avatar Aug 08 '22 16:08 fetsorn

I don't think wrap.info should contain URI information. Instead we could add this info at resolution time in the client, so that the Wrapper class knows about it's URI

nerfZael avatar Aug 10 '22 19:08 nerfZael

Left a comment here: https://github.com/polywrap/technical-council/issues/69#issuecomment-1211143701

I think the best way to do this is to allow wrappers to use their current URI within their code. For example, this.uri inside of a wasm wrapper.

dOrgJelli avatar Aug 10 '22 19:08 dOrgJelli

I think we could maybe replace the current method name, and args with Context This means it'd be preencoded. Also, when talking about wrapper URI and caller URI we need to know about which URIs we're referring to and which to add to the context:

  • A wrapper can have multiple URIs (ens -> ipfs) are we treating the final URI as the wrapper URI or the origin one before URI resolution? Are we also including all the redirects during resolution?
  • Same thing for the caller URI, which of those URIs is the "caller"?

nerfZael avatar Aug 17 '22 13:08 nerfZael

I think we could maybe replace the current method name, and args with Context

Preencoding context along with the args is a good point. I don't know what's cleaner, to pass this type separately or with the args. Either way we should consider that in the future we might pass additional metadata with the context, e.g. instance id for concurrency management.

are we treating the final URI as the wrapper URI or the origin one before URI resolution?

The final URI is "closer" to the invocable instance, but it might be inconsistent with URI usage in the rest of the app. I'd say the original "canonical" URI of caller and this is sufficient, because any call to that URI would follow the redirects and resolve properly anyways. In other words, if an invoker calls client.invoke({uri: "ens/wrapper.eth", method, args}), the invocable should always receive "ens/wrapper.eth" as InvokeContext.thisUri.

Are we also including all the redirects during resolution?

Do we need the resolution history in the Context if it is already accessible via the client plugin?

fetsorn avatar Aug 17 '22 17:08 fetsorn

Okay after doing more thinking about this here's what I'm thinking:

  • Wrappers can indeed have multiple URIs (ex: domain.eth -> ipfs/QmHASH)
  • We want to support 2 ways of accessing the wrapper's URI:
    1. Get the canonical "uri" which is the ending URI of the URI resolution path (i.e. ipfs/QmHash)
    2. Get the URI resolution path, so you can see what other URIs are associated with this wrapper
  • We do not want to do a "push" model here, where we push this URI data into every wasm wrapper by default.
  • We should support a "pull" interface, where a wrapper can get (1) and (2) described above.

Some psuedo code for what this might look like (in AssemblyScript):

import { URIs } from "./wrap";

// get the final URI: "wrap://ipfs/QmHASH"
URIs.this();

// get the URI resolution: ["wrap://ens/domain.eth", "wrap://ipfs/QmHash"]
URIs.path()

Another name for URIs could be UriResolution or UriResolver. Thoughts @fetsorn @nerfZael ?

dOrgJelli avatar Sep 09 '22 19:09 dOrgJelli

NOTE: the above solution does not account for "parallel paths" where you may have multiple URI resolution paths that point to the same resulting URI. Example:

ens/a.eth -> ipfs/QmHash
ens/b.eth -> ipfs/QmHash

Could be solved by simply changing path() to paths(), or even supporting both methods.

dOrgJelli avatar Sep 09 '22 19:09 dOrgJelli

@fetsorn @ramilexe can you please explain the OmniBlocks use-case that requires this feature? It will make it easier to know how to best support it.

dOrgJelli avatar Sep 11 '22 13:09 dOrgJelli

One cool things about this feature is that it would enable recursive wrapper calls.

For example, the IPFS resolver wrapper uses two wrappers and a plugin for parallel resolution requests.

sync call: wrapper_a --> wrapper_b async call: wrapper_a --> concurrency plugin --> wrapper_b

But if it knew its own URI, it could call its own implementation of the ipfs cat method.

sync call: wrapper_a async call: wrapper_a --> concurrency plugin --> wrapper_a

krisbitney avatar Nov 29 '22 16:11 krisbitney

:100: agreed, this is hyper useful for concurrent calls to a wrapper's own exported functions.

dOrgJelli avatar Dec 09 '22 00:12 dOrgJelli