-
Notifications
You must be signed in to change notification settings - Fork 254
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
Add more dynamic decoding support to subxt
#406
Comments
Related, I also have some similar code in my |
Also related: |
subxt
into three crates to focus on both static and dynamic uses.subxt
Here's my shot at putting together a list of dynamic decoding/encoding features that I'd like to see supported in the Are there any other areas that you'd like me to think about when looking into this dynamic/runtime side of things? Feedback and use cases that you'd like supported but aren't currently are very welcome! GoalsTo be able to use
An example of a tool I'd like to be able to build on top of this is a CLI tool that will let you build and submit FeaturesAdd a runtime Value type to represent the data we can send/get back.See Must haves:
(The desub-current code covers the Nice to haves:
(The desub-current Value implements these serde traits already.) Metadata API: Ths ability to explore available storage/calls/events/constants.To satisfy our goal, we want to be able to inspect, at runtime, the calls that we can make to a
All of these basically involve providing a nice interface to the metadata. The ability to dynamically build and submit a transaction, receiving back a dynamic result.Once we can explore the available calls, we'd like to be able to actually interact with use subxt::dynamic::{ Value, tx };
let signer = PairSigner::new(AccountKeyring::Alice.pair());
let dest: MultiAddress<AccountId32> = AccountKeyring::Bob.to_account_id().into();
// `tx` is just a helper to provide Value::Variant types of the right shape.
let transaction = tx("Balances", "Transfer")
// Anything that can be serialized to a Value type can be provided here, though
// perhaps we can also accept anything that can be SCALE encoded and store that in some
// opaque SCALE encoded blob type? (perhaps .scale_param and .value_param). Needs thought;
// SCALE types would not be debuggable and inspectable in the same way, so I'd start without.
.param(dest)
.param(10_000u128)
// to allow for things like UIs and CLI tools, a dynamic Value type (see desub-current)
// would enable us to pass values without knowing the type. Encoded with the help of Metadata.
.param(Value::variant("Foo", vec![Value::primitive(10u8)]))
.build();
// transaction is essentially a Value::Variant type at this point, outer variant Balances,
// inner variant Transfer with whatever params provided.
let val = api
.dynamic()
.tx(transaction)
// We can check whether the transaction is valid before trying to send it
.check()?
// Re-use the same logic for submitting and such as much as practical.
.sign_and_submit_then_watch(&signer)
.await?
.wait_for_finalized_success()
.await?;
// val would be a dynamic Value type. If we rely on features from desub-current's Valeu type,
// we can Deserialize this into any compatible static type, or just display it in whatever format
// we prefer. Dyanmic storage queriesAs with building dynamic transactions, let's expose an API to allow us to construct dynamic use subxt::dynamic::{ Value, storage };
// Similarly to transacitons, perhaps we have some type
// which embeds the Value params along with the hashers
// and such needed to make a storage request
let storage_entry = storage("Staking", "Bonded")
.param(something, Hasher::TwoX_128)
.param(Value::primitive(123u8), Hasher::Blake2_256);
// We get back a Value representing whatever is in storage.
let val = api
.dynamic()
.storage(storage_entry)
// As with transactions, some way to check this against current
// metadata might be useful?
.check()?
.submit()
.await? Dynamic event decodingWe can already iterate over events dynamically to find ones of interest and ignore others, which requires
|
I'm particularly interested in this part. It would be good to replace the similar code I have in |
Currently
subxt
is optimised towards the compile-time oriented codegen usage; we generate an interface and then use that interface to query compatible nodes. This has many advantages (you benefit from compile-time errors, IDE support, performance and more). The main downside is that the compile-time generated interface is unable to work across different, differing nodes/chains in a general way (parts of it may continue to work, and others will not).Having the ability to dynamically query nodes across different chains can be very useful in some cases, for example exploratory tooling which wants to interrogate the available interfaces, or tooling akin to polkagot.js which needs to be able to provide a dynamic interface to interact with arbitrary substrate based chains.
These two directions (compiletime, static codegen and dynamic, runtime interaction) are not mutually exclusive either. They would both benefit from the same client (JSONRPC transport/API) code for instance. Another overlap is that
subxt
is used to provide a static interface to a single pallet for thecargo-contracts
tool, which means being able to dynamically decodeEvents
emitted from other pallets that it does not know about (rather than erroring because it's unable to statically decode them).So, my proposal is that we work towards something like the following:
subxt-static
(which itself usessubxt-macro
andsubxt-codegen
),subxt-dynamic
andsubxt-client
.subxt-static
is justsubxt
as it stands (with a little runtime decoding moved out of it).subxt-dynamic
provides similar functionality to the above, but at runtime. It contains the logic needed to dynamically encode and decode things.subxt-client
splits out the JSONRPC client API as it currently stands, so that it can be shared between the above.subxt-metadata
, too; perhaps not initially)cargo-contracts
use case requires that we can dynamically decode (and throw away) any events we don't care about until we get to the one we're looking for (with egfind_event::<MyEvent>()
).The text was updated successfully, but these errors were encountered: