Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

middleware base #129

Open
wants to merge 96 commits into
base: dev
Choose a base branch
from
Open

middleware base #129

wants to merge 96 commits into from

Conversation

bekauz
Copy link
Contributor

@bekauz bekauz commented Dec 20, 2024

closes #126 , #120

introduces a base implementation of Valence Types to be used in programs.

new additions:

  • contracts/middleware/broker - type registry gateway meant to enable runtime upgrades to type registries
  • contracts/middleware/type-registries - actual type registries where developers can add new types to be used in valence
  • contracts/libraries/icq-querier - icq querier library which uses the broker for getting the KVKey needed for registering an ICQuery
  • packages/middleware-utils - utils used to define the common api for middleware system
  • local-interchaintest/examples/middleware_icq_test - e2e test showcasing the middleware usage to icq an osmosis gamm pool, parse it into a valence xyk type, and get its price

while some parts are still a little rough around the edges, I think it makes sense to put this pr up now to get some feedback around some key logic in this flow.

Broker

I expect the same broker to be used for any and all type registries or other types of plugins we may want to enable, as long as they comply with the expected interface.
Brokers wrap around the type registry api and relay the requests to the specified (or default=latest) version of the type registry. New type registries can be added to brokers during runtime to enable new types/functionality without requiring any upgrades from programs relying on a given broker.

Type Registries

This is where I spent the most time. In particular, contracts/middleware/type-registries/osmosis/osmo-26-0-0/src/definitions.

In mod.rs, we have a register_types! macro call. Currently it looks like this:

register_types! {
    "/osmosis.gamm.v1beta1.Pool" => {
        native_type: Pool,
        adapter: OsmosisXykPool,
        to_valence: ValenceType::XykPool,
    },
    "/cosmos.bank.v1beta1.QueryBalanceResponse" => {
        native_type: QueryBalanceResponse,
        adapter: OsmosisBankBalance,
        to_valence: ValenceType::BankBalance,
    }
}

Under the hood the macro generates a query handler that is used in the type registry contract:

pub fn query(_deps: Deps, _env: Env, msg: RegistryQueryMsg) -> StdResult<Binary> {
    handle_query(msg)
}

My thinking here was to minimize the lines of code needed to have a unified interface.
It can be seen as a map which maps the external type url (designator) to a set of functionality (plugins) we wish to enable for that type.
Zooming in on the gamm pool entry, we are basically saying:

"/osmosis.gamm.v1beta1.Pool" type url represents the osmosis::gamm::v1beta1::Pool native type which should map into the ValenceType::XykPool using the OsmosisXykPool adapter.

Valence Types are defined in utils packages and are out of developer (who are implementing the type registry) control.
Currently the set of enabled types is:

pub enum ValenceType {
    XykPool(ValenceXykPool),
    BankBalance(ValenceBankBalance),
}

Adapter is the only thing the developer needs to write, see example at contracts/middleware/type-registries/osmosis/osmo-26-0-0/src/definitions/gamm_pool.

Currently it feels like most (if not all) of those macro fields can be seen as optional. No type being registered should be expected to implement every adapter possible.
For example, we could introduce an evm_adapter field which could be used to specify the type/struct/function that knows how to do evm serde. It would only be useful for a small subset of all types we may be dealing with.

One thing to note here is that in order to maintain the unified api, these macros will embed every possible adapter for every type registry. Meaning, if we tried to call some evm_serde method on a type that does not have that adapter implemented, it would return an error along the lines of "evm adapter is not implemented for this type".

@hxrts
Copy link
Contributor

hxrts commented Dec 23, 2024

I think the pretty name of the valence type should be an alias that we manage for convenience, but by default these types should be content addressed somehow. This allows anyone to add new valence types and external types to the registry and mapping them, but prevents squatting something like ValenceType:VaultDeposit.

So I'm an external developer I add the following to the registry:

  • sha256digest(valence_type)
  • sha256digest(evm_type)

The concatenation of these two content addresses concat(sha256digest(valence_type), "_", sha256digest(evm_type)) gives me a unique mapping between types which I can use in my program.

And then as a convenience, a multi-sig we own can create human readable aliases for a unique sha256digest(valence_type).

After which developers can use something like ValenceType:VaultDeposit_EVMType:VaultDeposit.

What's here is already a substantial addition, so we may want to address this is a separate PR.

@hxrts
Copy link
Contributor

hxrts commented Dec 23, 2024

we should probably rename icq-querier to neutron-icq-querier to avoid future conflicts

Comment on lines +111 to +112
prost = { version = "0.13.3", default-features = false, features = [ "prost-derive" ] }
prost-types = { version = "0.13.3", default-features = false }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe add the default-features flag in the contract?

@@ -0,0 +1 @@
# ICQ-querier library
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prob worth adding something here

_info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response<NeutronMsg>, LibraryError> {
Ok(Response::default())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set contract version here?

keys: vec![query_kv_key],
transactions_filter: String::new(),
connection_id,
update_period: 5,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should update_period be hardcoded?

Comment on lines +133 to +137
let mut resp = vec![];
for entry in ASSOCIATED_QUERY_IDS.range(deps.storage, None, None, Order::Ascending) {
resp.push(entry?);
}
to_json_binary(&resp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can just do

        .filter_map(Result::ok)
        .map(|(_, entry)| entry)
        .collect()

for these queries

@@ -0,0 +1,3 @@
[alias]
wasm = "build --release --lib --target wasm32-unknown-unknown"
schema = "run --bin schema"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you create the schemas for both contracts? This way linter won't complain when we merge into main

Comment on lines +20 to +21
prost = { workspace = true }
prost-types = { workspace = true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would add the default-features = false here like for serde-json-wasm (linked to prev comment)

Comment on lines +33 to +34
osmosis-std = "0.26.0"
osmosis-std-derive = "0.26.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we have these in workspace
nit2: indent.

_info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, MiddlewareError> {
Ok(Response::default())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as other contract. Add versioning for migration.

Comment on lines +47 to +49
/*
OSMOSIS POOL

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leftover?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants