-
Notifications
You must be signed in to change notification settings - Fork 121
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
contract-transcoder
for non-ink projects
#659
Comments
contract-transcoder
for non-ink projects
Hi @extraymond, apologies for the delay I have been away on holiday. I am probably the best person to answer your questions, I will get to it this week. |
No problem, currently I tried converting solang ABI to InkProject by abusing serde_json, which isn't the best approach for this IMO. It would be nice to share something with InkProject, which could basically be a subset of InkProject which the constructor don't require anything to have rust type known in compile time, such as Registry, TypeSpec and Layout and so on. So we can construct the internal directly without breaking the promises of scale-codec. |
I have created an experimental PR paritytech/scale-info#164 which allows constructing a Can you try this branch out to see if it suits your needs? It will require patching in that |
I think this goes into the right direction. How would I then use the type created in your example/test as message parameter type? (Including an end-to-end example somewhere in the docs would be very helpful for newcomers I guess, however I'm aware this is not yet finished |
Thanks I'll try to play with this. |
You will need to pass your constructed |
Thanks @ascjones 😊 I was tinkering with this yesterday but couldn't figure out a (sane) way without changing |
For the purposes of experimenting to see if this approach works, I would just add that constructor in your local |
I got this close to working by adding a simple custom constructor to error[E0308]: mismatched types
--> src/main.rs:60:47
|
60 | let meta_type = MetaType::new_custom(123, runtime_meta_type);
| -------------------- ^^^^^^^^^^^^^^^^^ expected `&str`, found struct `std::string::String`
| |
| arguments to this function are incorrect
|
= note: expected fn pointer `fn() -> Type<MetaForm<&'static str>>`
found fn item `fn() -> Type<MetaForm<std::string::String>> {runtime_meta_type}` |
Ok I've done this with paritytech/scale-info@4500520. |
This might be a bit more of a rabbit hole than I thought... I can start a PR for |
I might have a better idea, hold your horses while I give it a go. |
Ok try the latest of my branch. Key difference is that The reason we need all that is because of substrate runtimes which uses the minimal version of |
Nice, that should make it a lot simpler indeed! I try it out later today, thanks! |
I can make my example compile with some slight changes to |
Yes that looks good, you could probably even make it a non breaking change if you make the |
Gave it a shot. ❯ cargo test -p ink_lang
Compiling ink_lang v4.0.0 (/home/cyrill/mess/ink/crates/lang)
error[E0282]: type annotations needed
--> crates/lang/tests/unique_topics.rs:19:1
|
19 | #[ink::contract]
| ^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `D` declared on the associated function `docs`
|
= note: this error originates in the attribute macro `ink::contract` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider specifying the generic arguments
|
19 | #[ink::contract]::<[_; 0], Str>
| +++++++++++++++
For more information about this error, try `rustc --explain E0282`.
error: could not compile `ink_lang` due to previous error |
Maybe I've found the middle-ground, by using a With that latest commit |
I tried using the scale-info and ink-metadata fork mentioned above, and currently when trying to generate runtime types for solang, I'm facing the issue of not able to reference another type within a type. So for example in solang, the ast can reference another type which should contain most of the types: // For example for `[u8; 32]` ink-metadata, we can do this:
// this is possible for known type:
let meta = meta_type::<[u8; 32]>;
let spec = TypeSpec::new_from_ty(meta);
// or
let spec = TypeSpec::new::<[u8; 32]>()
// But if we have some type created earlier for example type_id_1 -> TypeSpec::new_from_ty(meta_of_1)
// and want to create [type_1; 32]
let inner_meta = todo!("get the meta from a cache or hashmap");
let arr = TypeDefArray::new(inner_meta, 32);
let ty = Type::from(arr);
// this is impossible due to `fn() - Type` can not capture variable, therefore it cannot reference external meta.
let meta = MetaType::new_custom(type_id, || { ty });
// needed for the below
let spec = TypeSpec::new_from_ty(meta);
let m = MessageParamSpec::new().of_type(spec); Ideally solang's ast can be converted into mostly three groups:
This is my current working branch: |
Yes, I think as the final step (hopefully), we should think about opening up the EDIT: With this change it would be possible to use a closure that captures values. What do you think @ascjones @extraymond ? |
Okay so my experiment to attempt to use the existing static Having looked at @extraymond's working branch, I think we should attempt again the path of constructing the Essentially it is putting the full responsibility to the caller of producing the type ids and putting them in the correct order in the I assume since Note that I have made all those fields public as a temporary measure, if this is the correct approach I will update the builders API to allow construction with |
@ascjones |
I tried the latest commit on scale-info, and while it's possible to create portable registry now. From InkProject's POV, all the Spec's constructors are bounded to have something similar as Which means currently it's not possible to use most of the methods from ink_metadata to construct a new instance, compared to previously where everything looks the same, also there's several trait and type that's used to control the life-cycle of construction, such as |
For the purposes of this experiment, could you do as I did and use a fork of |
Thanks, after opening up most of the fields for all the needed types, currently blocked because |
I've made |
If I open most of the types on All needed information can be passed from solang to InkProject, with only Currently instead of using Hash from |
Awesome! So the next step is to hide all the fields again and update all the builders in |
I updated the constructors and builders in |
Alternatively I can open the PR for review, if it is going into the right direction. |
If it provides a working solution to this problem, then we should definitely open it up for review. However it will depend on paritytech/scale-info#164 being updated to hide the fields again and update all the builders to make them generic (ideally in a backwards compatible way). I may not get to that in the next few days, so feel free to push to my branch there or open your own PR. |
Sounds reasonable, thanks for the feedback. Sure, I'll have a look into the builders from scale-info as well 👍 |
Info
background:
Thanks for splitting the contract-transcode crate into a separate crate! We're a new team working on substrate which uses pallet-contracts underneath.
We're currently trying to build helper libraries to bring solang based contracts closer to the metadata formats ink based contract used.
And having able to reuse as much code from cargo-contract as possible so that
solang
users can benefit from using tooling specifically build for ink as well. Devs report to us that when usingpolkadot.js
based tools, they have problem using contracts other than primitive types.My question is around ways to produce the same internal data structure and feed it to
cargo-transcode
.To my understanding, currently
contract-transcode
relied on two parts to work:attempts
1. follow InkProject
I tried forking solang and in the last step when building the
solang::ABI
, I tried to create aInkProject
andPortableRegistry
as close as possible.Currently unsuccessful due to:
meta_type::<T: TypeInfo>
which we're only able to provide primitive types whichsolang::abi::Type
uses. For Composite and Enum it's not possible to generate the meta_type due to not being a rust data structure.2. convert ABI
I tried converting existing ABI and build InkProject with its internal data.
Currently also impossible because for
InkProject::new($args)
, the args are all generic acrossSpec<T: Form=MetaForm>
which means it needs to know the type at compile time again.3. inplace replacement with serialize <-> deserialize
all fields in InkProject's currently only require
<Form=PortableForm>
, and all those types have <Serialize, Deserialize> on it.Without attempting to fork
scale-info
:<T:Form=MetaForm>
locally with<T: Form=PortableForm>
serde_json::to_writer(LocalInkProject)
InkProject
withserde_json::from_reader
Currently also failed due to some internal serde bonds not satisfied.
questions
Currently I'm having difficulty to directly reuse
cargo-transcode
for non-ink projects due to unable to produceInkProject
from either end. Alsocustom_env_transcoder
didn't work because it'll need the types to be in the PortableRegistry before hand.InkProject
is the desired behavior. How feasible would it be to inject runtime types into Registry without knowing the concrete type?The text was updated successfully, but these errors were encountered: